feat(ui): add Lobby and Main Menu Body (#38)
Co-authored-by: LQ63 <lkhermann@web.de> Reviewed-on: #38 Co-authored-by: Janis <janis.e.20@gmx.de> Co-committed-by: Janis <janis.e.20@gmx.de>
This commit is contained in:
@@ -1,50 +1,71 @@
|
||||
@(player: de.knockoutwhist.player.AbstractPlayer, logic: de.knockoutwhist.control.GameLogic)
|
||||
@import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.TrickUtil
|
||||
|
||||
@(player: de.knockoutwhist.player.AbstractPlayer, gamelobby: logic.game.GameLobby)
|
||||
|
||||
@main("Ingame") {
|
||||
<div id="ingame" class="game-field game-field-background">
|
||||
<h1>Knockout Whist</h1>
|
||||
<div id="nextPlayers">
|
||||
<p>Next Player:</p>
|
||||
<p>@logic.getPlayerQueue.get.duplicate().nextPlayer()</p>
|
||||
</div>
|
||||
<div id="firstCard">
|
||||
<div id="trumpsuit">
|
||||
<p>Trumpsuit: </p>
|
||||
<p>@logic.getCurrentRound.get.trumpSuit</p>
|
||||
<div class="container py-5">
|
||||
|
||||
<!-- Header Row -->
|
||||
<div class="row mb-4 text-center">
|
||||
<div class="col-md-4 text-start">
|
||||
<h4 class="fw-semibold mb-1">Current Player</h4>
|
||||
<p class="fs-5 text-primary">@gamelobby.getLogic.getCurrentPlayer.get.name</p>
|
||||
@if(!TrickUtil.isOver(gamelobby.getLogic.getCurrentMatch.get, gamelobby.getLogic.getPlayerQueue.get)) {
|
||||
<h4 class="fw-semibold mb-1">Next Player</h4>
|
||||
@for(nextplayer <- gamelobby.getLogic.getPlayerQueue.get.duplicate()) {
|
||||
<p class="fs-5 text-primary">@nextplayer</p>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Middle column without "Cards Played" -->
|
||||
<div class="col-md-4 text-center">
|
||||
<!-- You can leave this empty or add something else here if needed -->
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 text-end">
|
||||
<h4 class="fw-semibold mb-1">Trumpsuit</h4>
|
||||
<p class="fs-5 text-primary">@gamelobby.getLogic.getCurrentRound.get.trumpSuit</p>
|
||||
|
||||
<h5 class="fw-semibold mt-4 mb-1">First Card</h5>
|
||||
<div class="d-inline-block border rounded shadow-sm p-1 bg-light">
|
||||
@if(gamelobby.getLogic.getCurrentTrick.get.firstCard.isDefined) {
|
||||
@util.WebUIUtils.cardtoImage(gamelobby.getLogic.getCurrentTrick.get.firstCard.get) width="80px"/>
|
||||
} else {
|
||||
@views.html.render.card.apply("images/cards/1B.png")("Blank Card") width="80px"/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="firstCardObject">
|
||||
<p>First Card</p>
|
||||
@if(logic.getCurrentTrick.get.firstCard.isDefined) {
|
||||
@util.WebUIUtils.cardtoImage(logic.getCurrentTrick.get.firstCard.get)
|
||||
} else {
|
||||
@views.html.render.card.apply("images/cards/1B.png")("Blank Card")
|
||||
|
||||
<!-- Cards Played -->
|
||||
<div class="row justify-content-center g-3 mb-5">
|
||||
@for((cardplayed, player) <- gamelobby.getLogic.getCurrentTrick.get.cards) {
|
||||
<div class="col-auto">
|
||||
<div class="card text-center shadow-sm border-0" style="width: 7rem;">
|
||||
<div class="p-2">
|
||||
@util.WebUIUtils.cardtoImage(cardplayed) width="100%"/>
|
||||
</div>
|
||||
<div class="card-body p-2 bg-light">
|
||||
<small class="fw-semibold text-secondary">@player</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Player Hand at the BOTTOM -->
|
||||
<div class="row justify-content-center g-2 mt-4" id="card-slide">
|
||||
@for(i <- player.currentHand().get.cards.indices) {
|
||||
<div class="col-auto">
|
||||
<form action="@(routes.IngameController.playCard(gamelobby.id))" method="post" class="m-0 p-0">
|
||||
<input type="hidden" name="cardId" value="@i" />
|
||||
<button type="submit" class="btn btn-outline-light p-0 border-0 shadow-none">
|
||||
@util.WebUIUtils.cardtoImage(player.currentHand().get.cards(i)) width="120px"/>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>@logic.getCurrentPlayer.get has to play a card!</p>
|
||||
@if(logic.getCurrentTrick.get.cards.nonEmpty) {
|
||||
<p>Cards played</p>
|
||||
} else {
|
||||
<p id="invisible">Cards played</p>
|
||||
}
|
||||
|
||||
<div id="cardsplayed">
|
||||
@for((cardplayed, player) <- logic.getCurrentTrick.get.cards) {
|
||||
<div id="playedcardplayer">
|
||||
<p>@player</p>
|
||||
@util.WebUIUtils.cardtoImage(cardplayed)
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<p>Your cards</p>
|
||||
<div id="playercards">
|
||||
@for(card <- player.currentHand().get.cards) {
|
||||
@util.WebUIUtils.cardtoImage(card)
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
84
knockoutwhistweb/app/views/lobby/lobby.scala.html
Normal file
84
knockoutwhistweb/app/views/lobby/lobby.scala.html
Normal file
@@ -0,0 +1,84 @@
|
||||
@(user: Option[model.users.User], gamelobby: logic.game.GameLobby)
|
||||
|
||||
@main("Lobby") {
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="p-3 fs-1 d-flex align-items-center">
|
||||
<div class="text-center" style="flex-grow: 1;">
|
||||
Lobby-Name: @gamelobby.name
|
||||
</div>
|
||||
<form action="@(routes.IngameController.leaveGame(gamelobby.id))">
|
||||
<button type="submit" class="btn btn-danger ms-auto">Exit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="p-3 text-center fs-4">Playeramount: @gamelobby.getPlayers.size / @gamelobby.maxPlayers</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
|
||||
@if((gamelobby.getUserSession(user.get.id).host)) {
|
||||
@for(playersession <- gamelobby.getPlayers.values) {
|
||||
<div class="col-auto">
|
||||
<div class="card" style="width: 18rem;">
|
||||
<img src="@routes.Assets.versioned("images/profile.png")" alt="Profile" class="card-img-top w-50 mx-auto mt-3" />
|
||||
<div class="card-body">
|
||||
@if(playersession.id == user.get.id) {
|
||||
<h5 class="card-title">@playersession.name (You)</h5>
|
||||
<p class="card-text">Your text could be here!</p>
|
||||
<a href="#" class="btn btn-danger disabled" aria-disabled="true" tabindex="-1">Remove</a>
|
||||
} else {
|
||||
<h5 class="card-title">@playersession.name</h5>
|
||||
<p class="card-text">Your text could be here!</p>
|
||||
<form action="@(routes.IngameController.kickPlayer(gamelobby.id, playersession.id))" method="post">
|
||||
<button type="submit" class="btn btn-danger">Remove</button>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col text-center mt-3">
|
||||
<a href="@(routes.IngameController.startGame(gamelobby.id))" class="btn btn-success">Start Game</a>
|
||||
</div>
|
||||
</div>
|
||||
} else {
|
||||
@for(playersession <- gamelobby.getPlayers.values) {
|
||||
<div class="col-auto">
|
||||
<div class="card" style="width: 18rem;">
|
||||
<img src="@routes.Assets.versioned("images/profile.png")" alt="Profile" class="card-img-top w-50 mx-auto mt-3" />
|
||||
<div class="card-body">
|
||||
@if(playersession.id == user.get.id) {
|
||||
<h5 class="card-title">@playersession.name (You)</h5>
|
||||
<p class="card-text">Your text could be here!</p>
|
||||
} else {
|
||||
<h5 class="card-title">@playersession.name</h5>
|
||||
<p class="card-text">Your text could be here!</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col mt-3">
|
||||
<p class="text-center fs-4">Waiting for the host to start the game...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mt-1">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -1,20 +1,21 @@
|
||||
@()
|
||||
|
||||
@main("Login") {
|
||||
|
||||
<div class="login-box">
|
||||
<div class="card login-card p-4">
|
||||
<div class="card-body">
|
||||
<h3 class="text-center mb-4">Login</h3>
|
||||
<h3 class="text-center mb-4 text-body">Login</h3>
|
||||
|
||||
<form action="@routes.UserController.login_Post()" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" id="username" name="username" placeholder="Enter Username" required>
|
||||
<label for="username" class="form-label text-body">Username</label>
|
||||
<input type="text" class="form-control text-body" id="username" name="username" placeholder="Enter Username" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" placeholder="Enter password" required>
|
||||
<label for="password" class="form-label text-body">Password</label>
|
||||
<input type="password" class="form-control text-body" id="password" name="password" placeholder="Enter password" required>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
@@ -34,6 +35,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<script src="@routes.Assets.versioned("/javascripts/particles.js")"></script>
|
||||
<script>
|
||||
particlesJS.load('particles-js', 'assets/conf/particlesjs-config.json', function() {
|
||||
console.log('callback - particles.js config loaded');
|
||||
});
|
||||
</script>
|
||||
<div id="particles-js" style="background-color: rgb(182, 25, 36);
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@@ -3,24 +3,30 @@
|
||||
* handles the rendering of the page header and body tags. It takes
|
||||
* two arguments, a `String` for the title of the page and an `Html`
|
||||
* object to insert into the body of the page.
|
||||
*@
|
||||
*@
|
||||
@(title: String)(content: Html)
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
@* Here's where we render the page title `String`. *@
|
||||
<title>@title</title>
|
||||
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
|
||||
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@* And here's where we render the `Html` object containing
|
||||
* the page content. *@
|
||||
@content
|
||||
<body class="d-flex flex-column min-vh-100 game-field-background">
|
||||
<main>
|
||||
@* And here's where we render the `Html` object containing
|
||||
* the page content. *@
|
||||
@content
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
</footer>
|
||||
|
||||
<script src="@routes.Assets.versioned("javascripts/main.js")" type="text/javascript"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
|
||||
|
||||
32
knockoutwhistweb/app/views/mainmenu/creategame.scala.html
Normal file
32
knockoutwhistweb/app/views/mainmenu/creategame.scala.html
Normal file
@@ -0,0 +1,32 @@
|
||||
@(user: Option[model.users.User])
|
||||
|
||||
@main("Create Game") {
|
||||
@navbar(user)
|
||||
<form action="@routes.MainMenuController.createGame()" method="post" class="game-field-background">
|
||||
<div class="w-50 mx-auto">
|
||||
<div class="mt-3">
|
||||
<label for="lobbyname" class="form-label">Lobby-Name</label>
|
||||
<input type="text" class="form-control" id="lobbyname" name="lobbyname" placeholder="Lobby 1" required>
|
||||
</div>
|
||||
<div class="form-check form-switch mt-3">
|
||||
<input class="form-check-input" type="checkbox" id="visibilityswitch" disabled>
|
||||
<label class="form-check-label" for="visibilityswitch">public/private</label>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<label for="playeramount" class="form-label">Playeramount:</label>
|
||||
<input type="range" class="form-range text-body" min="2" max="7" value="2" id="playeramount" name="playeramount">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>2</span>
|
||||
<span>3</span>
|
||||
<span>4</span>
|
||||
<span>5</span>
|
||||
<span>6</span>
|
||||
<span>7</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 text-center">
|
||||
<button type="submit" class="btn btn-success">Create Game</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
@(user: Option[model.users.User])
|
||||
@main("Knockout Whist - Main Menu") {
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||
<div class="container-fluid">
|
||||
<div class="container d-flex justify-content-center">
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navBar" aria-controls="navBar" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navBar">
|
||||
<a class="navbar-brand" href="@routes.MainMenuController.mainMenu()">KnockOutWhist</a>
|
||||
<div class="collapse navbar-collapse justify-content-center" id="navBar">
|
||||
<a class="navbar-brand ms-auto" href="@routes.MainMenuController.mainMenu()">KnockOutWhist</a>
|
||||
<div class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<ul class="navbar-nav mb-2 mb-lg-0">
|
||||
@if(user.isDefined) {
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">Create Game</a>
|
||||
<a class="nav-link active" aria-current="page" href="@routes.MainMenuController.mainMenu()">Create Game</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" aria-disabled="true">Lobbies</a>
|
||||
@@ -53,4 +52,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
|
||||
@@ -1,63 +1,76 @@
|
||||
@()
|
||||
@(user: Option[model.users.User])
|
||||
|
||||
@main("Rules") {
|
||||
<div id="rules" class="game-field game-field-background">
|
||||
<table>
|
||||
<caption>Rules Overview and Equipment</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Section</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Players</td>
|
||||
<td>Two to seven players. The aim is to be the last player left in the game.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Aim</td>
|
||||
<td>To be the last player left in at the end of the game, with the object in each hand being to win a majority of tricks.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Equipment</td>
|
||||
<td>A standard 52-card pack is used.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Card Ranks</td>
|
||||
<td>In each suit, cards rank from highest to lowest: A K Q J 10 9 8 7 6 5 4 3 2.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deal (First Hand)</td>
|
||||
<td>The dealer deals seven cards to each player. One card is turned up to determine the trump suit for the round.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deal (Subsequent Hands)</td>
|
||||
<td>The deal rotates clockwise. The player who took the most tricks in the previous hand selects the trump suit. If there's a tie for the highest number of tricks, players cut cards to decide who calls trumps. One fewer card is dealt in each successive hand until the final hand consists of one card each.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Play</td>
|
||||
<td>The player to the dealer's left (eldest hand) leads the first trick. Any card can be led. Other players must follow suit if possible. A player with no cards of the suit led may play any card.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Winning a Trick</td>
|
||||
<td>The highest card of the suit led wins, unless a trump is played, in which case the highest trump wins. The winner of the trick leads the next.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Leading Trumps</td>
|
||||
<td>Some rules disallow leading trumps before the suit has been 'broken' (a trump has been played to the lead of another suit). Leading trumps is always permissible if a player holds only trumps.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Knockout</td>
|
||||
<td>At the end of each hand, any player who took no tricks is knocked out and takes no further part in the game.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Winning the Game</td>
|
||||
<td>The game is won when a player takes all the tricks in a round, as all other players are knocked out, leaving only one player remaining.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<td>Dog Life</td>
|
||||
<td>The first player who takes no tricks is awarded a "dog's life". In the next hand, that player is dealt one card and can decide which trick to play it to. Each time a trick is played the "dog" may either play the card or knock on the table and wait to play it later. If the dog wins a trick, the player to the left leads to the next and the dog re-enters the game properly in the next hand. If the dog fails, they are knocked out.</td>
|
||||
</table>
|
||||
@navbar(user)
|
||||
<div id="rules">
|
||||
<div class="container my-4">
|
||||
<div class="card shadow-sm rounded-3">
|
||||
<div class="card-header text-white text-center">
|
||||
<h4 class="mb-0 text-body">Game Rules Overview</h4>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover mb-0 align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th scope="col">Section</th>
|
||||
<th scope="col">Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Players</td>
|
||||
<td>Two to seven players. The aim is to be the last player left in the game.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Aim</td>
|
||||
<td>To be the last player left at the end of the game, with the object in each hand being to win a majority of tricks.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Equipment</td>
|
||||
<td>A standard 52-card pack is used.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Card Ranks</td>
|
||||
<td>In each suit, cards rank from highest to lowest: A K Q J 10 9 8 7 6 5 4 3 2.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deal (First Hand)</td>
|
||||
<td>The dealer deals seven cards to each player. One card is turned up to determine the trump suit for the round.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deal (Subsequent Hands)</td>
|
||||
<td>The deal rotates clockwise. The player who took the most tricks in the previous hand selects the trump suit. If there's a tie, players cut cards to decide who calls trumps. One fewer card is dealt in each successive hand until the final hand consists of one card each.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Play</td>
|
||||
<td>The player to the dealer's left (eldest hand) leads the first trick. Any card can be led. Other players must follow suit if possible. A player with no cards of the suit led may play any card.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Winning a Trick</td>
|
||||
<td>The highest card of the suit led wins, unless a trump is played, in which case the highest trump wins. The winner of the trick leads the next.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Leading Trumps</td>
|
||||
<td>Some rules disallow leading trumps before the suit has been 'broken' (a trump has been played to the lead of another suit). Leading trumps is always permissible if a player holds only trumps.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Knockout</td>
|
||||
<td>At the end of each hand, any player who took no tricks is knocked out and takes no further part in the game.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Winning the Game</td>
|
||||
<td>The game is won when a player takes all the tricks in a round, as all other players are knocked out, leaving only one player remaining.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Dog Life</td>
|
||||
<td>The first player who takes no tricks is awarded a "dog's life". In the next hand, that player is dealt one card and can decide which trick to play it to. Each time a trick is played the "dog" may either play the card or knock on the table and wait to play it later. If the dog wins a trick, the player to the left leads the next and the dog re-enters the game properly in the next hand. If the dog fails, they are knocked out.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
@(src: String)(alt: String)
|
||||
<img src="@routes.Assets.versioned(src)" alt="@alt"/>
|
||||
<img src="@routes.Assets.versioned(src)" alt="@alt"
|
||||
Reference in New Issue
Block a user