diff --git a/README.md b/README.md index 1fc6fa1..821a8a3 100644 --- a/README.md +++ b/README.md @@ -1,136 +1,69 @@ -**UWAGA! Zaczynając pracę nad projektem — nie róbcie forka. -Jedna osoba z zespołu (np. Mentor) powinna użyć przycisku `Use this template` i dodać innych członków zespołu jako Collaborators do tego repozytorium. -Mentorzy mogą dowolnie zmieniać zakres projektu lub zdecydować się na zupełnie inny temat.** - # CodersCamp 2020 - Projekt TypeScript -**CodersCamp (coderscamp.edu.pl) - Największy otwarty kurs programowania webowego** - -![Szachy - Ekrany](./.github/images/SzachyEkrany.png) -Proponowany projekt — Szachy (opis poniżej). - -### Zasady wykonywania projektu (wspólne dla wszystkich grup i mentorów): - -##### W projekcie każdy z uczestników powinien zaprezentować praktyczną znajomość poniższych zagadnień związanych z TypeScript: -- typy podstawowe -- definiowanie własnych typów -- składanie typów -- typy / klasy / interfejsy -- implementacja / dziedziczenie / kompozycja / implementacja interfejsu -- modyfikatory dostępu -- typy generyczne -- testy jednostkowe i TDD - -Do realizacji założeń projektowych nie używajcie żadnej biblioteki, która np. implementuje silnik szachów. Ten projekt ma za zadanie właśnie nauczyć jak planować takie systemy :) Wraz z mentorem spróbujcie się skupić na właściwej architekturze aplikacji i podziale odpowiedzialności. -Co więcej, coraz częściej w czasie rekrutacji programistów pojawia się etap "System Design" poleagający na dyskusji i projektowaniu rozwiązania jakiegoś prostego systemu. Częstym przykładem jest właśnie gra w szachy. -W zadaniach dodatkowych jest gra przeciwko komputerowi - oczywiście AI nie jest zakresem kursu, więc tutaj możecie użyć jakiegoś gotowca lub zaimplementować własny prosty algorytm - proponujemy np. MINIMAX :) -Powodzenia! - -##### W trakcie trwania projektu należy wyznaczyć w zespole następujące role -tak jak opisano w przypadku poprzedniego projektu. - -Product Owner & Dev Manager odpowiada za ustalenie zadań dla zespołu, które umożliwią wykonanie aplikacji zgodnie z wymaganiami. -Oczywiście nie musi, a nawet nie powinien tego robić sam (nieoceniona będzie pomoc Tech Leadera i oczywiście opinia Klienta - pamiętajcie o jego cennym czasie i nie angażujcie w każdą dyskusję). -Można zorganizować spotkanie osób pełniących role w zespole, albo nawet całego zespołu. -W tym projekcie dobrze też zacząć estymować zadania wspólnie z zespołem. Jednakże mentor może zaproponować swój tryb pracy. -Skupcie się na jakości wykonania i pracy zespołowej. Niektóre wymagania mogą przypominać Wam poprzedni projekt, więc czasem może być warto wykorzystać już posiadaną wiedzę. - -##### Sposób oceny projektu (i wszystkich kolejnych projektów na CodersCamp) -tak jak opisano w przypadku poprzedniego projektu. - -## Gra w Szachy -Teraz przechodzimy do przykładowego projektu, który został przygotowany przez organizatorów kursu. -Proponowany projekt pozwala na zastosowania większości umiejętności, jakie powinniście posiąść w trakcie przerabiania działu. -Jednakże jeśli macie pomysł na projekt podobnej skali, który spełni opisane na górze wymagania i czujecie się na siłach -w zdefiniowaniu funkcjonalności, przygotowaniu ekranów i podzieleniu go na zadania — to nic nie stoi na przeszkodzie, -aby wykonać np. coś związanego z zainteresowaniami Waszej grupy :) -Przykładem może być też jakaś inna gra — np. Chińczyk. Niech nic nie stoi na przeszkodzie waszej kreatywności. -Pamiętajcie tylko, że czas jest ograniczony i musicie zdążyć z aplikacją do prezentacji. Powodzenia! + +**CodersCamp (coderscamp.edu.pl) - Największy otwarty kurs programowania webowego** -Czas porzucić narrację CodersCamp i wcielić się w członka zespołu projektowego... - -### Założenia projektowe -W trakcie projektu stajecie przed większym (lub mniejszym — jak kto woli) wyzwaniem. -Teraz nie macie niestety ani linijki już gotowego kodu. Brak też podzielonych zadań. Swoją pracę zaczynacie w tzw. projekcie greenfield, czyli totalnie od zera. -Pozwala to na większą dowolność, ale też wymaga na początku większego nakładu pracy i jest wąskim gardłem. -Jako zespół musicie podjąć odpowiednie decyzje na samym początku i postarać się jak najszybciej umożliwić pracę wielu osobom naraz. - -Szachy są coraz bardziej popularne wśród przedsiębiorców. Odbywają się nawet Mistrzostwa Polski dla osób prowadzące własne działalności. -Niestety, obecna sytuacja z pandemią pokrzyżowała trochę plany zorganizowania kolejnych mistrzostw. -Po sukcesie waszego ostatniego projektu wiele osób z tego środowiska usłyszało o waszych usługach. -Dlatego wasz zespół został poproszony o przygotowanie mechanizmu szachów, który pomógłby w organizacji tych mistrzostw online. -Oczywiście jest to o wiele większy projekt, dlatego Wy odpowiadacie tylko za sam mechanizm szachów w przeglądarce. -Nie skupiacie się na kwestiach gry wielu graczy przez internet. Zostanie to na bazie waszego prototypu zrealizowanie później. - -Ponieważ aplikacja ma być sygnowana przez CodersCrew, spróbujcie przygotować ją zgodnie z identyfikacją wizualną stowarzyszenia - Brand Book znajdziecie [TUTAJ](https://www.behance.net/gallery/94155751/Brand-Book-Project). -Nie jest to konieczność, ale fajna możliwość wypróbowania swojej skuteczności z takim wymaganiem (które jest częste w praktyce). - - -Lista funkcjonalności, jakie należy zaimplementować w silniku gry: -1. Ruchy wszystkich bierek (wykonanie ruchu, jak i pokazywanie możliwych): - - Pionek - - Hetman - - Wieża - - Goniec - - Król. -1. Promowanie pionka na dowolną inną figurę (oprócz króla) na końcu planszy. -1. Roszada: https://pl.wikipedia.org/wiki/Roszada -1. Szachowanie króla: https://pl.wikipedia.org/wiki/Szach_(szachy) -1. Szach mat: https://pl.wikipedia.org/wiki/Mat_(szachy) -1. Kończenie gry przez Pat: https://www.chess.com/pl/article/view/czym-jest-pat-szachowe-terminy -1. Bicie w przelocie: https://www.chess.com/pl/article/view/bicie-w-przelocie-specjalne-ruchy-w-szachach -1. Możliwość cofania ruchów (aż do początkowego układu). +# Super Farmer Game + +Welcome to our digital version of a fantastic family game Super Farmer! +You are an animal herder, wishing to become a Super Farmer. Your animals breed and herd grows, bringing you profit. +You can exchange your animals for other species if you find this exchange profitable. +To become a Super Farmer you must gather livestock including at least one horse, cow, pig, sheep and rabbit. +However, be warned! In the neighborhood, the wolf and the fox are hunting for your animals. + +Version 1.0 +--- + +Hi there, We are The Front Znad Zatoki Gdańsk! 👋 + +Here's a link to the website, where you can check out our app: +https://front-znad-zatoki.github.io/super-farmer/ -Uwaga: Pamiętajcie, że na ruchy bierek, promocję pionka i możliwość roszady wpływa na szachowanie króla. Najlepiej zagrajcie kilka partii w zespole, żeby zapoznać się z tą domeną. No chyba, że macie w swoim zespole eksperta? -Dokładnie poznajcie domenę, w jakiej działa wasze oprogramowanie, czyli grę w szachy, aby nie wprowadzić jakiegoś zachowania niezgodnego z zasadami i żeby nic nie przeoczyć. -Starajcie się przewidzieć przypadki brzegowe i zaimplementujcie do nich odpowiednie testy. - -**Jeśli macie w swoim zespole osobę chętną na przygotowanie designów, to także możecie UI zrobić kompletnie inaczej.** -A jeśli nie, to możecie się wzorować na przedstawionych [TUTAJ - Link do Figma](https://www.figma.com/file/ZllWbpJCCCCKVl7QEfNWbl/CodersCamp2020.Project.TypeScript.Chess?node-id=4461%3A3896). -Jednakże brakuje takich rzeczy jak np. wczytywanie / zapisywanie partii, wyświetlanie możliwych ruchów, podświetlanie wybranego pionka, zaznaczenie szachowanego króla czy wybór podczas promowania pionka. Co powinniście zaprojektować w ramach wykonywania aplikacji. Na projekcie z Figmy znalazło się też kilka rzeczy związanych z dodatkowymi funkcjonalnościami. Szczegóły co będziecie realizować - ustalcie z klientem. - -Waszym zadaniem będzie zaimplementować aplikację, aby działała wg wymagań klienta, a także przygotować i wykonać -wersję responsywną aplikacji (dostosowaną do wyświetlania na Tabletach i Telefonach — możecie przygotować najpierw projekt interfejsu, lub od razu przejść do implementacji). -W celu zaprezentowania działania aplikacja musi być możliwa do odwiedzenia w internecie. -Klient nie chce ponosić za to żadnych dodatkowych kosztów, dlatego należy wykorzystać jedną z usług oferujących darmowe -uruchomienie takiej aplikacji (np. GitHub Pages lub Netlify). -Klient wymaga także, aby aplikacja nie tylko działała, ale była odpowiednio pokryta testami. -Naprawdę macie szczęście co do klienta! Wielu uważa testy za niepotrzebne i jedynie stratę pieniędzy. -A co znaczy „odpowiednio pokryta”, to już należy właśnie ustalić z samym Klientem :) - -## Możliwe usprawnienia i dodatkowe funkcjonalności: -Jeśli starczy czasu, dla własnego rozwoju warto rozważyć wykonanie poniższych funkcjonalności. - -1. Wczytywanie i zapisywanie stanu partii (szachownica, czas graczy itp.) - po wczytaniu musi być możliwe cofanie ruchów. Stan partii powinien zapisywać się automatycznie co wykonany ruch. -1. Tworzenie nowej partii z aktualnego stanu partii. Gra nie może być zakończona. -1. Tekstowe komentarze do gry (przykładowo): - - `Gracz Biały wykonał ruch "Koń z C1 na D3"` - - `Gracz Czarny dokonał promocji Pionka na Hetmana na polu A1. Szach białego Króla!` - - `Gracz Biały wykonał roszadę po stronie królowej.` -1. Możliwość wyboru nieskończonego czasu gry lub szachów błyskawicznych (czas ograniczony dla każdego z graczy). -1. Odliczanie czasu dla każdej ze stron (cofanie ruchu musi cofać czas do stanu sprzed ruchu) w przypadku szachów błyskawicznych. -1. Dodatkowy czas doliczany do limitu czasowego gracza za każdy ruch (propocjonalny do długości całej patrii). -1. Kończenie gry przez limit czasowy - gracz, któremu skończył się czas przegrywa. Nie rozpatrujemy przypadku remisu. -1. Dwie wersje językowe gry — Polska i Angielska. -1. Ładowanie stanu początkowego z np. notacji FEN (https://pl.wikipedia.org/wiki/Notacja_Forsytha-Edwardsa) i/lub tablicy emojis. -1. Zaimplementuj różne strategie Pat opisane na Wikipedii: https://pl.wikipedia.org/wiki/Pat Np. stare zasady mówiły, że pat powodował wygraną strony, która zapatowała przeciwnika. -1. Głosowe wykonywanie ruchów. Np. gracz mówi: "Pion na A3". - -## Dodatkowe zadania (wykraczające poza zakres kursu): -1. Rozgrywka z komputerem - sztuczna inteligencja. Można wykorzystać np. algorytm minimax. Skorzystajcie z źródeł: - - https://alialaa.com/blog/tic-tac-toe-js-minimax - - https://www.youtube.com/watch?v=l-hh51ncgDI - - https://www.freecodecamp.org/news/simple-chess-ai-step-by-step-1d55a9266977/ - - https://towardsdatascience.com/create-ai-for-your-own-board-game-from-scratch-minimax-part-2-517e1c1e3362 - - https://dev.to/zeyu2001/build-a-simple-chess-ai-in-javascript-18eg -1. Wykonanie testów E2E, przy użyciu odpowiedniego narzędzia. Proponujemy np. Cypress. - -Wszelkie inne dodane przez Was funkcjonalności czy usprawnienia infrastrukturalne należy przedstawić w README.md projektu :) -Template znajdziecie w poprzednim projekcie. - -## Porady odnośnie do projektu -- Warto zapozań się z możliwościami kończenia partii szachowych (nie wszystko jest wymagane). - - [How Chess Games Can End: 8 Ways Explained](https://www.chess.com/article/view/how-chess-games-can-end-8-ways-explained) -- Jako inspirację można wykorzystać też działanie szachów zaimplementowanych przez zespół mentora Marcina Wosia na poprzednim CodersCamp (UWAGA: Wymagania mogły ulec zmianie) - - https://captainobjective.github.io/chessGame/ -- Dla testów może warto wykorzystać trochę reprezentacji wizualnej. Co powiecie na emoji :) ? Post mentora Mateusza Nowaka. - - [Emoji-Driven Development | ZycieNaKodach.pl](https://zycienakodach.pl/tdd-dsl-szachy-emojis) +Try it yourself, maybe you deserve to be called a Super Farmer! + +--- + +:computer: MORE INFO (installation, rules and more) ➡️ +https://github.com/Front-znad-zatoki/super-farmer/wiki + +--- +:rocket: This is our second project launched together! + +:point_right: Contributors: + +:woman_technologist: Paulina https://github.com/paula0403 + +:man_technologist: Sebastian https://github.com/SebastianBabinski1 + +:woman_technologist: Weronika https://github.com/vieraboschkova + +:man_technologist: Dominik https://github.com/DominikNowak + +:woman_technologist: Aleksandra https://github.com/synowa + +:man_technologist: Sebastian https://github.com/Enessetere + +Special thanks to our mentor Aleksander! + +:man_teacher: https://github.com/Rednaxela700 + + --- + +:hammer_and_wrench: Languages and Tools: + +Visual Studio Code + +HTML5 + +CSS3 + +Sass + +JavaScript + +GitHub + +Terminal + +Typescript + +Lodash diff --git a/src/app/EmptyView.ts b/src/app/EmptyView.ts index 4d16f3b..0845d48 100644 --- a/src/app/EmptyView.ts +++ b/src/app/EmptyView.ts @@ -2,17 +2,11 @@ import { Render } from './utils/Render'; export abstract class EmptyView { protected view: HTMLElement; - protected viewContainer: HTMLElement; - constructor(isHidden = true) { - this.viewContainer = Render.elementFactory('div', { - className: 'view__container', + constructor(isPale = false) { + this.view = Render.elementFactory('div', { + className: `view${isPale ? ' view--pale' : ''}`, }); - this.view = Render.elementFactory( - 'div', - { className: `view${isHidden ? ' hidden' : ''}` }, - this.viewContainer, - ); } hide(): void { diff --git a/src/app/GameController.ts b/src/app/GameController.ts index 55f8f81..0d9c91b 100644 --- a/src/app/GameController.ts +++ b/src/app/GameController.ts @@ -36,9 +36,9 @@ export class GameController { this.gameProcessor.pauseTurn(); } - turnAlert(): void { - this.view.turnAlert(); - } + // turnAlert(): void { + // this.view.turnAlert(); + // } private isGameWon(): void { if (this.gameProcessor.checkWin()) { @@ -72,9 +72,9 @@ export class GameController { ); } - updateTimeRemaining(timeLeft: number): void { - this.view.updateRemainingTime(timeLeft); - } + // updateTimeRemaining(timeLeft: number): void { + // this.view.updateRemainingTime(timeLeft); + // } quitGame(): void { this.gameProcessor.quitGame(); diff --git a/src/app/GameView.ts b/src/app/GameView.ts index cbe1076..88afcc6 100644 --- a/src/app/GameView.ts +++ b/src/app/GameView.ts @@ -1,16 +1,18 @@ import { AnimalNames } from '../Enums/AnimalNamesEnum'; import { Player } from '../Player'; +import { Alert } from './components/Alert'; import { BankBoard } from './components/BankBoard'; import { PlayerPanel } from './components/PlayerPanel'; import { PlayersBoard } from './components/PlayersBoard'; import { Bank } from './logic/Bank'; import { Render } from './utils/Render'; import { ViewController } from './ViewController'; - -export class GameView { - private playerPanel: PlayerPanel; - // TODO: FIND OUT WHY THIS CREATES INSTANCE OF PLAYER PANEL IN CONTRUCTOR - constructor(private view: ViewController) { +import { AlertType } from '../Enums/AlertEnum'; +import { EmptyView } from './EmptyView'; +export class GameView extends EmptyView { + protected playerPanel: PlayerPanel; + constructor(private viewController: ViewController) { + super(true); this.playerPanel = new PlayerPanel(this); } @@ -19,37 +21,70 @@ export class GameView { currentPlayer: Player, bank: Bank, ): void { - const playersBoards = this.createPlayersBoards(players); - const playerPanel = this.createPlayerPanel(currentPlayer); - const endGameButton = this.createEndGameButton(); - const bankPanel = this.createBankPanel(bank); - Render.removeAllChildren('#sf-app'); - Render.render( - '#sf-app', + // const topRow = this.createTopRow(); + const gameBoardsAndPanel = this.createGameBoardsAndPanel( + players, + currentPlayer, + bank, + ); + + Render.removeAllChildren(this.view); + this.view.appendChild( Render.elementFactory( 'div', - { className: 'page-container' }, - playersBoards, - playerPanel, - Render.elementFactory( - 'div', - { className: 'bank__bar' }, - endGameButton, - Render.elementFactory( - 'div', - { id: 'bank-board' }, - bankPanel, - ), - ), + { className: 'game' }, + // topRow, + gameBoardsAndPanel, ), ); - this.setBackground(currentPlayer); - } + Render.render('#sf-app', this.view); + // this.viewContainer.append(topRow, gameBoardsAndPanel); + // Render.render('#sf-app', this.view); + // this.show(); + this.setColorAccents(currentPlayer); + } + + // private createTopRow() { + // const alertPanel = this.createAlertPanel(); + // const endGameButton = this.createEndGameButton(); + // const topRow = Render.elementFactory( + // 'div', + // { className: 'game__top-row' }, + // alertPanel, + // endGameButton, + // ); + // return topRow; + // } + private createGameBoardsAndPanel( + players: Player[], + currentPlayer: Player, + bank: Bank, + ) { + const playersBoards = this.createPlayersBoards(players); + const playerPanel = this.createPlayerPanel(currentPlayer); + const bankPanel = this.createBankPanel(bank); + const endGameButton = this.createEndGameButton(); + const banksAndPanel = Render.elementFactory( + 'div', + { className: 'game__side-panel' }, + endGameButton, + bankPanel, + playerPanel, + ); + return Render.elementFactory( + 'div', + { className: 'game__main' }, + playersBoards, + banksAndPanel, + ); + } private createPlayersBoards(players: Player[]): HTMLElement { + const alertPanel = this.createAlertPanel(); return Render.elementFactory( 'div', { className: 'player-boards__container' }, + alertPanel, ...players.map((player) => Render.elementFactory( 'div', @@ -64,18 +99,30 @@ export class GameView { } private createPlayerPanel(player: Player): HTMLElement { - this.playerPanel.setPlayer(player); - return this.playerPanel.createPlayerPanel(); + return this.playerPanel.createPlayerPanel(player); } private createEndGameButton() { + const crossInButton = Render.elementFactory( + 'p', + { + 'aria-hidden': 'true', + className: 'endgame__text', + }, + 'X', + ); const endGameButton = Render.elementFactory( 'button', - { className: 'button endgame' }, - 'End game', + { + className: 'button endgame', + 'aria-label': 'End game', + 'data-tooltip': 'END GAME', + }, + crossInButton, ); + endGameButton.addEventListener('click', () => { - this.view.endGame(); + this.viewController.endGame(); }); return endGameButton; } @@ -84,63 +131,72 @@ export class GameView { return new BankBoard().renderBankBoard(bank); } - private setBackground(player: Player): void { - (document.querySelector( - '.page-container', - ) as HTMLElement).style.background = player.theColor; + private createAlertPanel(): HTMLElement { + let alertContainer = document.querySelector( + '.alert', + ) as HTMLElement; + if (!alertContainer) alertContainer = Alert.createElement(); + // TODO: connect with other methods to display the right alert + Alert.updateAlert('Lorem ipsum dolor sei', AlertType.CRITICAL); + return alertContainer; + } + + private setColorAccents(player: Player): void { + document + .querySelectorAll('.player-panel__buttons .button') + .forEach((element) => { + (element as HTMLElement).style.borderColor = player.theColor; + }); + // TODO: change to borders and font colors } handleRoll(): void { - this.view.handleRoll(); + this.viewController.handleRoll(); } handleTrade(): void { - this.view.handleTrade(); + this.viewController.handleTrade(); } displayRollResult( diceResults: AnimalNames[], playerGain: [AnimalNames, number][], + player: Player, ): void { - this.playerPanel.displayRollResult(diceResults, playerGain); - this.renderPlayerPanel(); - } - - private renderPlayerPanel(): void { - Render.removeAllChildren('#player-board'); - Render.render( - '#player-board', - ...this.playerPanel.createPanelBoard(), + this.playerPanel.displayRollResult( + diceResults, + playerGain, + player, ); } - updateRemainingTime(timeLeft: number): void { - this.playerPanel.updateTime(timeLeft); - } + // updateRemainingTime(timeLeft: number): void { + // this.playerPanel.updateTime(timeLeft); + // } stopTimer(): void { - this.view.stopTimer(); + this.viewController.stopTimer(); } nextTurn(): void { - this.view.nextTurn(); + this.viewController.nextTurn(); } - turnAlert(): void { - this.playerPanel.turnAlert(); - } + // turnAlert(): void { + // this.playerPanel.turnAlert(); + // } pauseTurn(): void { - this.view.pauseTurn(); + this.viewController.pauseTurn(); } disableTrade(): void { this.playerPanel.disableTrade(); } - refreshHerd(bank: Bank): void { - this.playerPanel.refreshHerd(); - Render.removeAllChildren('#bank-board'); - Render.render('#bank-board', this.createBankPanel(bank)); - } + // refreshHerd(bank: Bank): void { + // this.playerPanel.refreshHerd(); + // Render.removeAllChildren('#bank-board'); + // Render.render('#bank-board', this.createBankPanel(bank)); + // } } diff --git a/src/app/MenuView.ts b/src/app/MenuView.ts index 040ce4e..88599af 100644 --- a/src/app/MenuView.ts +++ b/src/app/MenuView.ts @@ -8,7 +8,7 @@ export class MenuView extends EmptyView { private modeModal: ModeView; private menuViewContent: HTMLElement; constructor(private viewController: ViewController) { - super(false); + super(); const backCallback = () => this.show(); const submitCallback = ( isDynamic: boolean, @@ -26,7 +26,7 @@ export class MenuView extends EmptyView { this.createStartButton(), this.createFooter(), ); - this.viewContainer.appendChild(this.menuViewContent); + this.view.appendChild(this.menuViewContent); } displayMenu(): void { diff --git a/src/app/ModeView.ts b/src/app/ModeView.ts index 4583ee9..451ac27 100644 --- a/src/app/ModeView.ts +++ b/src/app/ModeView.ts @@ -25,7 +25,7 @@ export class ModeView extends EmptyView { backCallback: CallbackNoParam, submitCallback: CallbackTwoParam, ) { - super(); + super(true); this.addPlayerButton = Render.elementFactory( 'button', { @@ -53,7 +53,7 @@ export class ModeView extends EmptyView { this.submitCallback = submitCallback; Render.childrenInjector( - this.viewContainer, + this.view, this.modeForm, this.generateButtons(), ); diff --git a/src/app/ViewController.ts b/src/app/ViewController.ts index 483489a..ef92126 100644 --- a/src/app/ViewController.ts +++ b/src/app/ViewController.ts @@ -37,8 +37,6 @@ export class ViewController { this.menuView.displayMenu(); } - /*TODO: CHECK IF AI NEEDED, CONNECT WITH CALLBACK THAT PASSES PLAYERS*/ - /* TODO: CONSIDER USING DEFAULT CONFIG ALWAYS, JUST CHANGE ALREADY CREATED CONFIG IN CASE ITS A DYNAMIC MODE*/ launchGame(players: PlayerDTO[], isModeDynamic?: boolean): void { const config: Configuration = isModeDynamic === true @@ -71,17 +69,23 @@ export class ViewController { this.gameView.renderGameView(players, currentPlayer, bank); this.gameController?.startTurn(); } - - updateRemainingTime(timeLeft: number): void { - this.gameView.updateRemainingTime(timeLeft); - } + // TODO: CHECK IF STILL NECESSARY + // updateRemainingTime(timeLeft: number): void { + // this.gameView.updateRemainingTime(timeLeft); + // } handleRoll(): void { this.gameController?.breed(); } updateRollResults({ rollResult, gain }: RollResult): void { - this.gameView.displayRollResult(rollResult, gain); + if (this.gameController) { + this.gameView.displayRollResult( + rollResult, + gain, + this.gameController.theGame.theCurrentPlayer, + ); + } } handleTrade(): void { @@ -91,10 +95,10 @@ export class ViewController { displayWinModal(player: Player): void { Render.render('body', this.winModal.createWinModal(player)); } - - turnAlert(): void { - this.gameView.turnAlert(); - } + // TODO: CHECK IF STILL NECESSARY + // turnAlert(): void { + // this.gameView.turnAlert(); + // } displayRulesModal(): void { // TODO: display rules @@ -116,7 +120,8 @@ export class ViewController { processAfterTrade(): void { this.runTimer(); - this.refreshHerd(); + // TODO: CHECK IF STILL NECESSARY + // this.refreshHerd(); this.disableTrade(); this.checkIfGameIsWon(); } @@ -155,9 +160,10 @@ export class ViewController { this.gameView.disableTrade(); } - refreshHerd(): void { - this.gameView.refreshHerd(this.gameController?.getBank() as Bank); - } + // TODO: CHECK IF STILL NECESSARY + // refreshHerd(): void { + // this.gameView.refreshHerd(this.gameController?.getBank() as Bank); + // } checkIfGameIsWon(): void { this.gameController?.checkIfGameIsWon(); diff --git a/src/app/components/Alert.ts b/src/app/components/Alert.ts index c4d7213..71cfa52 100644 --- a/src/app/components/Alert.ts +++ b/src/app/components/Alert.ts @@ -31,13 +31,19 @@ export class Alert { Render.removeAllChildren(this.alert); switch (alertType) { case AlertType.INFO: - this.alert.style.backgroundColor = '#3E8Ed0'; + this.alert.style.background = + // 'linear-gradient(to right, #3E8Ed0D4, #fff0)'; + '#3E8Ed0D4'; break; case AlertType.WARN: - this.alert.style.backgroundColor = '#FFE08A'; + this.alert.style.background = + // 'linear-gradient(to right, #FFE08AD4, #fff0)'; + '#FFE08AD4'; break; case AlertType.CRITICAL: - this.alert.style.backgroundColor = '#F14668'; + this.alert.style.background = + // 'linear-gradient(to right, #F14668D4, #fff0)'; + '#F14668D4'; break; default: this.alert.style.backgroundColor = 'transparent'; @@ -49,7 +55,7 @@ export class Alert { alt: `${alertType}-alert`, }); const text = Render.elementFactory( - 'div', + 'p', { className: 'alert__text' }, `${message}`, ); diff --git a/src/app/components/BankBoard.ts b/src/app/components/BankBoard.ts index 28df247..2f5297f 100644 --- a/src/app/components/BankBoard.ts +++ b/src/app/components/BankBoard.ts @@ -1,30 +1,29 @@ import { Render } from '../utils/Render'; import { Bank } from '../logic/Bank'; -import { ConvertAnimalName } from '../utils/ConvertAnimalName'; export class BankBoard { /* returns Bank board with animals and counts */ renderBankBoard(bank: Bank): HTMLElement { const bankView = Render.elementFactory('div', { - className: 'bank__board', + className: 'bank', }); - const bankText = Render.elementFactory( - 'div', - { className: 'bank__board__text' }, - `BANK:`, - ); const bankHerd = bank.theHerd.theAnimals.map(([animal, count]) => Render.elementFactory( 'div', - { className: 'bank__board__container' }, - ConvertAnimalName.toHTMLElement( - animal.theName, - 'bank__board__img', + { className: 'bank__item' }, + Render.elementFactory('img', { + className: 'bank__img', + alt: animal.theName.toLowerCase(), + src: `${animal.theImagePath}`, + }), + Render.elementFactory( + 'p', + { className: 'bank__count' }, + `${count}`, ), - `x${count}`, ), ); - Render.childrenInjector(bankView, bankText, ...bankHerd); + Render.childrenInjector(bankView, ...bankHerd); return bankView; } } diff --git a/src/app/components/PlayerPanel.ts b/src/app/components/PlayerPanel.ts index ccc6bd6..d2697b4 100644 --- a/src/app/components/PlayerPanel.ts +++ b/src/app/components/PlayerPanel.ts @@ -1,118 +1,33 @@ import { Player } from '../../Player'; import { Render } from '../utils/Render'; -import { flatten } from 'lodash'; +// import { flatten } from 'lodash'; import { AnimalNames } from '../../Enums/AnimalNamesEnum'; import { GameView } from '../GameView'; import { ConvertAnimalName } from '../utils/ConvertAnimalName'; import { Animal } from '../../Animals/Animal'; export class PlayerPanel { - private player: Player; /** * Creates PlayerPanel based on data given * @param view accepts instance of View componenet */ - constructor(private view: GameView) { - // TODO: FIND OUT WHY IS THIS PANEL CREATED TOGETHER WITH THE LANDING PAGE - this.player = new Player('', '', ''); - } - - setPlayer(player: Player): void { - this.player = player; - } + constructor(private view: GameView) {} /** * Creates player panel and returns it as HTMLElement */ - createPlayerPanel(): HTMLElement { + createPlayerPanel(player: Player): HTMLElement { return Render.elementFactory( 'div', { className: 'player-panel', - style: `background-color: ${this.player.theColor};`, + style: `background-color: ${player.theColor};`, }, - this.createPlayerBoard(), this.createResultWindow(), this.createButtonPanel(), ); } - private createPlayerBoard(): HTMLElement { - return Render.elementFactory( - 'div', - { - id: 'player-board', - className: 'player-panel__board', - }, - ...this.createPanelBoard(), - ); - } - - refreshHerd(): void { - Render.removeAllChildren('#player-board'); - Render.render('#player-board', ...this.createPanelBoard()); - } - - createPanelBoard(): HTMLElement[] { - return [ - Render.elementFactory( - 'div', - { className: 'player-panel__info' }, - Render.elementFactory('img', { - src: this.player.theAvatar, - alt: `${this.player.theName}-avatar`, - className: 'avatar-icon', - }), - this.createPlayerDetails(), - ), - Render.elementFactory( - 'div', - { id: 'time-left', className: 'player-panel__time' }, - `Time left: `, - ), - this.createPlayerHerd(), - ]; - } - - private createPlayerDetails(): HTMLElement { - return Render.elementFactory( - 'div', - { className: 'player-panel__details' }, - Render.elementFactory('p', {}, 'Current player:'), - Render.elementFactory( - 'p', - { className: 'player-panel__name' }, - `${this.player.theName}`, - ), - ); - } - - private createPlayerHerd(): HTMLElement { - return Render.elementFactory( - 'div', - { className: 'player-panel__herd' }, - ...flatten( - this.convertAnimalsToHTML(this.player.theHerd.theAnimals), - ), - ); - } - - private convertAnimalsToHTML( - animals: [Animal, number][], - ): HTMLElement[] { - return animals.map(([animal, count]) => - Render.elementFactory( - 'div', - { className: 'player-panel__result--container' }, - ConvertAnimalName.toHTMLElement( - animal.theName, - 'player-panel__image', - ), - `x${count}`, - ), - ); - } - private createResultWindow(): HTMLElement { return Render.elementFactory( 'div', @@ -171,6 +86,7 @@ export class PlayerPanel { displayRollResult( diceResults: AnimalNames[], playerGain: [AnimalNames, number][], + player: Player, ): void { const diceResult = Render.elementFactory( 'div', @@ -184,51 +100,51 @@ export class PlayerPanel { ConvertAnimalName.toHTMLElement(name, 'player-panel__image'), ), ); - Render.render( - '.player-panel__result', - diceResult, + // Render.render( + // '.player-panel__result', + // diceResult, + // Render.elementFactory( + // 'div', + // {}, + // Render.elementFactory( + // 'h3', + // { className: 'player-panel__result--gain' }, + // `${player.theName} gains:`, + // ), + // ...this.convertAnimalsToHTML( + // playerGain.map(([animal, count]) => [ + // ConvertAnimalName.toAnimalObject(animal), + // count, + // ]), + // ), + // ), + // ); + this.view.stopTimer(); + // setTimeout(() => this.hideTimer(), 10); + } + private convertAnimalsToHTML( + animals: [Animal, number][], + ): HTMLElement[] { + return animals.map(([animal, count]) => Render.elementFactory( 'div', - {}, - Render.elementFactory( - 'h3', - { className: 'player-panel__result--gain' }, - `${this.player.theName} gains:`, - ), - ...this.convertAnimalsToHTML( - playerGain.map(([animal, count]) => [ - ConvertAnimalName.toAnimalObject(animal), - count, - ]), + { className: 'player-panel__result--container' }, + ConvertAnimalName.toHTMLElement( + animal.theName, + 'player-panel__image', ), + `x${count}`, ), ); - this.view.stopTimer(); - setTimeout(() => this.hideTimer(), 10); - } - - private hideTimer(): void { - (document.querySelector( - '#time-left', - ) as HTMLElement).style.display = 'none'; - } - - /** - * Updates timer on player panel - * @param timeLeft accepts number value for time left - */ - updateTime(timeLeft: number): void { - const timer = document.querySelector('#time-left') as HTMLElement; - timer.innerText = `Time left: ${timeLeft} sec.`; } - turnAlert(): void { + turnAlert(player: Player): void { Render.render( '#sf-app', Render.elementFactory( 'div', { className: 'exclamation' }, - `${this.player.theName}'s turn has passed!`, + `${player.theName}'s turn has passed!`, ), ); } diff --git a/src/app/components/TradeModal.ts b/src/app/components/TradeModal.ts index e479388..514e4af 100644 --- a/src/app/components/TradeModal.ts +++ b/src/app/components/TradeModal.ts @@ -1,3 +1,4 @@ +import { Animal } from '~src/Animals/Animal'; import { CallbackNoParam } from '~src/Interfaces/CallbackInterface'; import { AnimalNames } from '../../Enums/AnimalNamesEnum'; import { Player } from '../../Player'; @@ -13,6 +14,7 @@ export class TradeModal extends EmptyModal { private warning: HTMLElement; private backButton: HTMLElement; private player: Player; + private header: HTMLElement; /** * @param trade instance of Trade @@ -32,6 +34,11 @@ export class TradeModal extends EmptyModal { this.bankView = Render.elementFactory('div', { className: 'trade__player-wrapper', }); + this.header = Render.elementFactory( + 'h2', + { className: 'trade__heading' }, + 'Pick the animals and the amount you want to exchange', + ); this.tradeForm = Render.elementFactory( 'form', { @@ -40,21 +47,33 @@ export class TradeModal extends EmptyModal { className: 'trade', }, this.playerView, - Render.elementFactory('input', { - type: 'submit', - value: 'Trade', - className: 'trade__submit', - }), + Render.elementFactory( + 'button', + { + type: 'submit', + className: 'trade__submit', + }, + Render.elementFactory('img', { + alt: 'exchange', + src: './static/images/ui/exchange-dark.svg', + }), + Render.elementFactory('p', {}, 'Exchange'), + ), this.bankView, ); this.warning = Render.elementFactory('p', { className: 'warning', }); - this.backButton = Render.elementFactory('button', {}, 'back'); + this.backButton = Render.elementFactory( + 'button', + { className: 'trade__back' }, + '+', + ); Render.childrenInjector( this.modalContainer, - this.tradeForm, + this.header, this.warning, + this.tradeForm, this.backButton, ); } @@ -136,24 +155,29 @@ export class TradeModal extends EmptyModal { Render.elementFactory( 'div', { className: 'trade__row' }, - Render.elementFactory( - 'label', - { - for: `${isBank ? 'bank' : 'player'}_${ - animal.theName - }`, - }, - `${animal.theName}: ${count}`, - ), - Render.elementFactory('input', { - type: 'number', - id: `${isBank ? 'bank' : 'player'}_${animal.theName}`, + Render.elementFactory('img', { name: `${isBank ? 'bank' : 'player'}_${ animal.theName }`, - min: '0', - max: `${count}`, + src: animal.theImagePath, + alt: animal.theName, + className: 'trade__player-herd--image', }), + Render.elementFactory( + 'p', + { className: 'trade__player-herd--count' }, + `x ${count}`, + ), + this.createInputBox(isBank, animal, count), + Render.elementFactory( + 'div', + { className: 'trade__player-herd--buttons' }, + ...this.createButtons( + isBank, + animal.theName.replace(' ', '_'), + count, + ), + ), ), ); } @@ -165,9 +189,90 @@ export class TradeModal extends EmptyModal { return animalsRows; } + private createInputBox( + isBank: boolean, + animal: Animal, + count: number, + ): HTMLElement { + const input = Render.elementFactory('input', { + type: 'text', + id: `${isBank ? 'bank' : 'player'}_${animal.theName.replace( + ' ', + '_', + )}`, + name: `${isBank ? 'bank' : 'player'}_${animal.theName}`, + className: 'trade__player-herd--input', + value: '0', + pattern: '\\d+', + }) as HTMLInputElement; + input.addEventListener('change', () => { + const value = parseInt(input.value); + if (value > count) { + input.value = `${count}`; + } + }); + return input; + } + + private createButtons( + isBank: boolean, + animal: string, + count: number, + ): HTMLElement[] { + const buttons: HTMLElement[] = []; + buttons.push(this.createSingleButton(1, isBank, animal, count)); + buttons.push(this.createSingleButton(5, isBank, animal, count)); + buttons.push(this.createSingleButton(-1, isBank, animal, count)); + buttons.push(this.createSingleButton(-5, isBank, animal, count)); + return buttons; + } + + private createSingleButton( + value: number, + isBank: boolean, + animal: string, + count: number, + ): HTMLElement { + const button = Render.elementFactory( + 'button', + { + type: 'button', + className: 'trade__player-herd--button', + }, + `${value < 0 ? value : '+' + value}`, + ); + button.addEventListener('click', () => + this.changeValue(value, isBank, animal, count), + ); + return button; + } + + private changeValue( + value: number, + isBank: boolean, + animal: string, + count: number, + ): void { + const input = document.querySelector( + `#${isBank ? 'bank' : 'player'}_${animal}`, + ) as HTMLInputElement; + const inputValue = parseInt(input.value); + if (value < 0) { + if (inputValue > 0 && inputValue >= Math.abs(value)) { + input.value = `${inputValue + value}`; + } + } else { + const newValue = inputValue + value; + if (newValue <= count) { + input.value = `${value + inputValue}`; + } + } + } + private formDataIntoTuples(formData: FormData): [Offer[], Offer[]] { const offer: Offer[] = []; const target: Offer[] = []; + console.log(formData); for (const [key, value] of formData.entries()) { const numberOfAnimals = parseInt(value.toString()); const [player, animal] = key.split('_'); diff --git a/src/app/logic/Bank.ts b/src/app/logic/Bank.ts index 89490ed..ca8d3d5 100644 --- a/src/app/logic/Bank.ts +++ b/src/app/logic/Bank.ts @@ -6,6 +6,6 @@ export class Bank extends Player { constructor( banksHerdConfig: HerdConfigInterface[] = defaultBankConfig, ) { - super('bank', '', '', banksHerdConfig); + super('Bank', '', '', banksHerdConfig); } } diff --git a/src/app/logic/GameProcessor.ts b/src/app/logic/GameProcessor.ts index 5a0dbf1..eb95ec1 100644 --- a/src/app/logic/GameProcessor.ts +++ b/src/app/logic/GameProcessor.ts @@ -20,18 +20,20 @@ export class GameProcessor { const turnTimer = setInterval(() => { if (!this.game.theTimer.running) { clearInterval(turnTimer); - if (Math.round(this.game.theTimer.theTurnTimeLeft) === 0) { - this.gameController.turnAlert(); - } + // TODO: CHECK IF UPDATE NEEDED FOR PLAYER BOARD + // if (Math.round(this.game.theTimer.theTurnTimeLeft) === 0) { + // this.gameController.turnAlert(); + // } if (!this.game.theTimer.hasGameEnded) { setTimeout(() => { this.gameController.nextPlayer(); }, 3000); } } - this.gameController.updateTimeRemaining( - Math.round(this.game.theTimer.theTurnTimeLeft), - ); + // TODO: CHECK IF UPDATE NEEDED FOR PLAYER BOARD + // this.gameController.updateTimeRemaining( + // Math.round(this.game.theTimer.theTurnTimeLeft), + // ); }, 50); } diff --git a/src/app/logic/defaultGameConfiguration.ts b/src/app/logic/defaultGameConfiguration.ts index 7ac030e..3489c4e 100644 --- a/src/app/logic/defaultGameConfiguration.ts +++ b/src/app/logic/defaultGameConfiguration.ts @@ -5,7 +5,7 @@ import { GameConfigInterface } from '../../Interfaces/GameConfigInterface'; export const defaultGameConfiguration: GameConfigInterface = { mode: GameModes.STATIC, - roundTimeInSeconds: 15, + roundTimeInSeconds: 15000, playersConfig: [ { name: 'Carlos Santanos', diff --git a/src/app/manuals/PlayerPanelDemo.ts b/src/app/manuals/PlayerPanelDemo.ts index 72f6867..635d457 100644 --- a/src/app/manuals/PlayerPanelDemo.ts +++ b/src/app/manuals/PlayerPanelDemo.ts @@ -12,7 +12,7 @@ export class PlayerPanelDemo { '#44AF95', ); const pp = new PlayerPanel(viewController.theGameView); - pp.setPlayer(player); - Render.render('#sf-app', pp.createPlayerPanel()); + // pp.setPlayer(player); + Render.render('#sf-app', pp.createPlayerPanel(player)); } } diff --git a/src/app/manuals/TradeModalDemo.ts b/src/app/manuals/TradeModalDemo.ts index 3622328..a38df94 100644 --- a/src/app/manuals/TradeModalDemo.ts +++ b/src/app/manuals/TradeModalDemo.ts @@ -23,7 +23,6 @@ export class TradeModalDemo { player.theHerd.addAnimalsToHerd(AnimalNames.RABBIT, 20); player.theHerd.addAnimalsToHerd(AnimalNames.SHEEP, 5); player.theHerd.addAnimalsToHerd(AnimalNames.PIG, 5); - player.theHerd.addAnimalsToHerd(AnimalNames.COW, 2); player.theHerd.addAnimalsToHerd(AnimalNames.HORSE, 1); const modal = new TradeModal( trade, diff --git a/static/images/ui/exchange-dark.svg b/static/images/ui/exchange-dark.svg new file mode 100644 index 0000000..051a18b --- /dev/null +++ b/static/images/ui/exchange-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/ui/exchange.svg b/static/images/ui/exchange.svg new file mode 100644 index 0000000..400c951 --- /dev/null +++ b/static/images/ui/exchange.svg @@ -0,0 +1,3 @@ + + + diff --git a/styles/_global.scss b/styles/_global.scss index 9245982..786297d 100644 --- a/styles/_global.scss +++ b/styles/_global.scss @@ -1,12 +1,14 @@ +@import './variables'; * { box-sizing: border-box; padding: 0; margin: 0; - font-family: 'Roboto', sans-serif; + font-family: $font-family; } + #sf-app { height: 100vh; - background: url(/static/images/ui/background.png) no-repeat; + background: url('/static/images/ui/background.png') no-repeat; background-size: cover; } #sf-app::after { diff --git a/styles/_variables.scss b/styles/_variables.scss index ca30efd..65256f8 100644 --- a/styles/_variables.scss +++ b/styles/_variables.scss @@ -1,7 +1,9 @@ //Fonts $font-family: 'Roboto', sans-serif; $font-size: 24px; -$font-weight: 700; +$font-weight-primary: 700; +$font-weight-secondary: 500; +$color: #203739; //Colors $color-primary: #fefefe; diff --git a/styles/components/_alert.scss b/styles/components/_alert.scss index 293aa7e..15f7815 100644 --- a/styles/components/_alert.scss +++ b/styles/components/_alert.scss @@ -1,8 +1,12 @@ .alert { + position: absolute; + top: -62px; display: flex; + width: 100%; + align-items: center; border-radius: 0.25rem; transition: all 0.7s ease-in-out; - + // flex: 5; &__icon { width: auto; height: 1.75rem; @@ -10,9 +14,6 @@ } &__text { - display: inline-flex; - margin: 0.5rem; font-size: 1rem; - line-height: 2rem; } } diff --git a/styles/components/_bankBoard.scss b/styles/components/_bankBoard.scss index f0d37bc..a5abfa2 100644 --- a/styles/components/_bankBoard.scss +++ b/styles/components/_bankBoard.scss @@ -1,28 +1,26 @@ .bank { - &__board { - display: inline-flex; - width: 90vw; - align-content: space-around; - align-items: center; - justify-content: space-around; - background-color: wheat; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding-top: 1rem; + background-color: $color-primary; + border-radius: $border-radius; - &__container { - } - - &__text { - display: inline; - font-weight: 700; - } - - &__img { - height: 3rem; - } + &__item { + display: flex; + flex-basis: 50%; + justify-content: center; + padding-bottom: 1rem; } - - &__bar { - position: absolute; - bottom: 0; - display: inline-flex; + &__count { + padding-top: 1rem; + padding-left: 0.5rem; + color: $color; + font-family: $font-family; + font-weight: $font-weight-secondary; + } + &__img { + height: 3rem; } } diff --git a/styles/components/_components.scss b/styles/components/_components.scss index 2e0f444..1cbcb49 100644 --- a/styles/components/_components.scss +++ b/styles/components/_components.scss @@ -1,4 +1,4 @@ -@import './view'; +@import './gameView'; @import './playersBoard'; @import './modal'; @import './menu'; diff --git a/styles/components/_emptyView.scss b/styles/components/_emptyView.scss index 423d518..483bcb3 100644 --- a/styles/components/_emptyView.scss +++ b/styles/components/_emptyView.scss @@ -1,6 +1,8 @@ .view { height: 100vh; - &__container { - height: 100vh; + padding: 40px; + + &--pale { + background-color: rgba(255, 255, 255, 0.8); } } diff --git a/styles/components/_gameView.scss b/styles/components/_gameView.scss new file mode 100644 index 0000000..e7871f1 --- /dev/null +++ b/styles/components/_gameView.scss @@ -0,0 +1,151 @@ +// .view { +// &__container { +// } +// } +.input__name { + display: block; + width: 150px; + height: 40px; + padding: 10px; + margin: 20px auto 0; +} +.container-img { + display: flex; + width: 700px; + justify-content: space-around; + margin: 50px auto; + &__avatar { + width: 70px; + height: 70px; + cursor: pointer; + } +} +.container-game { + display: flex; + height: 300px; + flex-direction: column; + align-items: center; + justify-content: space-around; + padding: 50px; +} +.container-buttons { + display: flex; + width: 350px; + justify-content: space-between; +} +.button { + background: rgb(250, 250, 250); + cursor: pointer; + &:hover { + background: #71cfd7; + } +} + +.player-boards { + &__container { + position: relative; + display: grid; + gap: 24px 24px; + grid-template-columns: repeat(2, 1fr); + } + + &__board { + border: 1px black solid; + background-color: white; + border-radius: 0.3rem; + } +} + +.exclamation { + position: absolute; + top: calc(60vh - 10px - 0.5em); + left: 20vw; + padding: 10px; + border: 5px dotted red; + background-color: white; + color: green; + font-size: 28px; + font-weight: bold; +} + +.endgame { + position: absolute; + top: -52px; + right: 8px; + border: none; + -webkit-appearance: none; + -moz-appearance: none; + background-color: transparent; + font-size: 1rem; + font-weight: 600; + text-align: right; + &:hover { + background-color: transparent; + } + &:focus { + outline: 1px solid transparent; + outline-offset: -4px; + } + &__text { + transform: scaleX(1.35); + } + &[data-tooltip] { + text-decoration: none; + } + &[data-tooltip]:after { + position: absolute; + right: -6px; + bottom: 0; + padding: 3px 30px 3px 8px; + background: rgba(250, 250, 250, 0.5); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + -ms-border-radius: 4px; + -o-border-radius: 4px; + border-radius: 4px; + color: black; + content: attr(data-tooltip); + font-size: 12px; + opacity: 0; + -webkit-transition: all 0.5s ease-out; + -moz-transition: all 0.5s ease-out; + -ms-transition: all 0.5s ease-out; + -o-transition: all 0.5s ease-out; + transition: all 0.5s ease-out; + white-space: nowrap; + } + &[data-tooltip]:hover:after, + &[data-tooltip]:hover:before { + opacity: 1; + } +} + +.game { + display: flex; + width: 100%; + height: 100%; + flex-direction: column; + justify-content: space-between; + padding-top: 40px; + &__top-row, + &__main { + display: flex; + } + &__top-row { + position: relative; + justify-content: space-between; + margin-bottom: 20px; + } + &__main { + position: relative; + height: 100%; + justify-content: space-between; + } + &__side-panel { + display: flex; + min-width: 250px; + flex-direction: column; + justify-content: space-between; + margin-left: 40px; + } +} diff --git a/styles/components/_menu.scss b/styles/components/_menu.scss index e845be6..89b071f 100644 --- a/styles/components/_menu.scss +++ b/styles/components/_menu.scss @@ -2,7 +2,6 @@ display: flex; height: 100%; flex-direction: column; - padding: 80px; &__header { font-family: $font-family; } @@ -17,7 +16,7 @@ background: none; font-family: $font-family; font-size: $font-size; - font-weight: $font-weight; + font-weight: $font-weight-primary; outline: none; &:hover { color: $color-hover; @@ -34,7 +33,7 @@ color: $color-primary; font-family: $font-family; font-size: 30px; - font-weight: $font-weight; + font-weight: $font-weight-primary; letter-spacing: 0.3rem; line-height: 8rem; outline: none; @@ -49,5 +48,5 @@ color: $color-primary; font-family: $font-family; font-size: $font-size; - font-weight: $font-weight; + font-weight: $font-weight-primary; } diff --git a/styles/components/_modal.scss b/styles/components/_modal.scss index ddef96b..58c71bf 100644 --- a/styles/components/_modal.scss +++ b/styles/components/_modal.scss @@ -16,6 +16,7 @@ &__container { // Display & Box Model / + position: relative; display: flex; flex-direction: column; justify-content: space-between; diff --git a/styles/components/_playerPanel.scss b/styles/components/_playerPanel.scss index 944849c..0f10292 100644 --- a/styles/components/_playerPanel.scss +++ b/styles/components/_playerPanel.scss @@ -1,8 +1,9 @@ .player-panel { display: flex; - width: 100vw; - min-height: 40vh; - flex-grow: 1 1 1; + height: 100%; + flex: 1; + flex-direction: column; + justify-content: space-between; &__board { position: relative; @@ -41,10 +42,7 @@ } &__result { - width: 30vw; - padding: 0.5rem; - text-align: center; - + // position: absolute; &--dice { margin-top: 2rem; } @@ -60,16 +58,10 @@ &__buttons { display: flex; - width: 10vw; flex-direction: column; } } -.btn { - width: 100%; - height: 50%; -} - .avatar-icon { display: inline; height: 3rem; diff --git a/styles/components/_playersBoard.scss b/styles/components/_playersBoard.scss index d029b5d..a78eea9 100644 --- a/styles/components/_playersBoard.scss +++ b/styles/components/_playersBoard.scss @@ -16,7 +16,8 @@ } &__herd { display: flex; - align-items: center; + // align-items: center; + flex-wrap: wrap; &__img { width: 2.5rem; margin-left: 50px; diff --git a/styles/components/_tradeModal.scss b/styles/components/_tradeModal.scss index a127deb..00606d4 100644 --- a/styles/components/_tradeModal.scss +++ b/styles/components/_tradeModal.scss @@ -1,29 +1,107 @@ .trade { display: grid; height: 100%; - grid-template-columns: 2fr 1fr 2fr; + column-gap: 1rem; + grid-template-columns: 2fr 1.5fr 2fr; + + &__heading { + margin-bottom: 3.3rem; + font-size: 1.5rem; + } &__player-herd { display: flex; flex-direction: column; + align-items: center; + justify-content: center; row-gap: 1em; + + &--count { + align-self: center; + margin: auto 2rem auto 0.5rem; + } + + &--image { + width: auto; + height: 3rem; + align-self: center; + } + + &--input { + width: 2rem; + height: 2rem; + align-self: center; + margin-right: 2rem; + text-align: center; + } + + &--buttons { + display: grid; + width: 5rem; + height: 5rem; + align-content: space-around; + justify-content: space-around; + grid-template-columns: 1fr 1fr; + } + + &--button { + width: 2rem; + height: 2rem; + border: none; + border-radius: 50%; + + &:focus { + outline: none; + } + } } &__row { display: grid; + grid-template-columns: repeat(4, 1fr); } &__player-heading { padding-bottom: 1em; - text-transform: uppercase; } &__submit { - height: 4em; + height: 5em; + align-self: center; + border: none; + margin: 0 2rem; + background-color: #71cfd7; + border-radius: 1rem; + + &:focus { + outline: none; + } + } + + &__back { + position: absolute; + top: 1rem; + right: 1rem; + width: 2.1rem; + height: 2.1rem; + border: none; + background-color: white; + border-radius: 50%; + font-size: 1.5rem; + font-weight: 700; + transform: rotate(45deg); + + &:focus { + outline: none; + } } } .warning { - background-color: yellow; - font-size: 26px; + position: absolute; + top: 5.5rem; + left: calc(50% - 14rem); + margin-bottom: 1rem; + background-color: #ffe08a; + font-size: 1.2rem; } diff --git a/styles/components/_view.scss b/styles/components/_view.scss deleted file mode 100644 index ad2a03e..0000000 --- a/styles/components/_view.scss +++ /dev/null @@ -1,82 +0,0 @@ -.input__name { - display: block; - width: 150px; - height: 40px; - padding: 10px; - margin: 20px auto 0; -} -.container-img { - display: flex; - width: 700px; - justify-content: space-around; - margin: 50px auto; - &__avatar { - width: 70px; - height: 70px; - cursor: pointer; - } -} -.container-game { - display: flex; - height: 300px; - flex-direction: column; - align-items: center; - justify-content: space-around; - padding: 50px; -} -.container-buttons { - display: flex; - width: 350px; - justify-content: space-between; -} -.button { - // display: block; - // width: 120px; - // height: 30px; - // margin: 0 auto; - background: rgb(250, 250, 250); - cursor: pointer; - &:hover { - background: rgb(250, 0, 0); - } -} - -.player-boards { - &__container { - display: flex; - height: 54vh; - flex-wrap: wrap; - align-content: stretch; - justify-content: space-between; - } - - &__board { - width: 49vw; - border: 1px black solid; - margin: 0.5rem; - background-color: white; - border-radius: 0.3rem; - } -} - -.exclamation { - position: absolute; - top: calc(60vh - 10px - 0.5em); - left: 20vw; - padding: 10px; - border: 5px dotted red; - background-color: white; - color: green; - font-size: 28px; - font-weight: bold; -} - -.endgame { - width: 10vw; - height: 3.3rem; -} - -.page-container { - width: 100vw; - height: 100vh; -}