diff options
Diffstat (limited to 'sw-ui/src/main/kotlin/org')
7 files changed, 350 insertions, 78 deletions
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Board.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Board.kt index c5d4dd4a..bd6a9c2f 100644 --- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Board.kt +++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Board.kt @@ -25,6 +25,7 @@ private const val yOffset = 21 fun RBuilder.boardComponent(board: Board) { styledDiv { css { + paddingTop = 3.rem width = 100.vw } tableCards(cardColumns = board.playedCards) diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/BoardSummary.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/BoardSummary.kt new file mode 100644 index 00000000..f6225765 --- /dev/null +++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/BoardSummary.kt @@ -0,0 +1,117 @@ +package org.luxons.sevenwonders.ui.components.game + +import kotlinx.css.* +import kotlinx.html.DIV +import org.luxons.sevenwonders.model.api.PlayerDTO +import org.luxons.sevenwonders.model.boards.Board +import org.luxons.sevenwonders.ui.components.gameBrowser.playerInfo +import react.RBuilder +import styled.StyledDOMBuilder +import styled.css +import styled.styledDiv +import styled.styledHr + +enum class BoardSummarySide( + val tokenCountPosition: TokenCountPosition, + val scienceCountPosition: TokenCountPosition, + val alignment: Align +) { + LEFT(TokenCountPosition.RIGHT, TokenCountPosition.RIGHT, Align.flexStart), + TOP(TokenCountPosition.OVER, TokenCountPosition.OVER, Align.flexStart), + RIGHT(TokenCountPosition.LEFT, TokenCountPosition.LEFT, Align.flexEnd) +} + +fun RBuilder.boardSummary( + player: PlayerDTO, + board: Board, + boardSummarySide: BoardSummarySide, + block: StyledDOMBuilder<DIV>.() -> Unit = {} +) { + styledDiv { + css { + display = Display.flex + flexDirection = FlexDirection.column + alignItems = boardSummarySide.alignment + padding(all = 0.5.rem) + backgroundColor = Color.paleGoldenrod.withAlpha(0.5) + } + val tokenSize = 2.rem + val countPosition = boardSummarySide.tokenCountPosition + + playerInfo(player, iconSize = 25) + styledHr { + css { + margin(vertical = 0.5.rem) + width = 100.pct + } + } + styledDiv { + css { + display = Display.flex + flexDirection = if (boardSummarySide == BoardSummarySide.TOP) FlexDirection.row else FlexDirection.column + alignItems = boardSummarySide.alignment + } + styledDiv { + css { + display = Display.flex + flexDirection = if (boardSummarySide == BoardSummarySide.TOP) FlexDirection.row else FlexDirection.column + alignItems = boardSummarySide.alignment + if (boardSummarySide == BoardSummarySide.TOP) marginRight = 1.rem else marginBottom = 1.rem + } + generalCounts(board, tokenSize, countPosition) + } + scienceTokens(board, tokenSize, boardSummarySide.scienceCountPosition) + } + block() + } +} + +private fun StyledDOMBuilder<DIV>.generalCounts( + board: Board, + tokenSize: LinearDimension, + countPosition: TokenCountPosition +) { + goldIndicator(amount = board.gold, imgSize = tokenSize, amountPosition = countPosition) + tokenWithCount( + tokenName = "laurel-blue", + count = board.bluePoints, + imgSize = tokenSize, + countPosition = countPosition, + brightText = countPosition == TokenCountPosition.OVER + ) + tokenWithCount( + tokenName = "military", + count = board.military.nbShields, + imgSize = tokenSize, + countPosition = countPosition, + brightText = countPosition == TokenCountPosition.OVER + ) +} + +private fun RBuilder.scienceTokens( + board: Board, + tokenSize: LinearDimension, + sciencePosition: TokenCountPosition +) { + tokenWithCount( + tokenName = "compass", + count = board.science.nbCompasses, + imgSize = tokenSize, + countPosition = sciencePosition, + brightText = sciencePosition == TokenCountPosition.OVER + ) + tokenWithCount( + tokenName = "cog", + count = board.science.nbWheels, + imgSize = tokenSize, + countPosition = sciencePosition, + brightText = sciencePosition == TokenCountPosition.OVER + ) + tokenWithCount( + tokenName = "tablet", + count = board.science.nbTablets, + imgSize = tokenSize, + countPosition = sciencePosition, + brightText = sciencePosition == TokenCountPosition.OVER + ) +} diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameScene.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameScene.kt index be6b0e50..64077359 100644 --- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameScene.kt +++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameScene.kt @@ -3,10 +3,10 @@ package org.luxons.sevenwonders.ui.components.game import com.palantir.blueprintjs.* import kotlinx.css.* import kotlinx.css.properties.* -import org.luxons.sevenwonders.model.Action -import org.luxons.sevenwonders.model.PlayerMove -import org.luxons.sevenwonders.model.PlayerTurnInfo +import org.luxons.sevenwonders.model.* import org.luxons.sevenwonders.model.api.PlayerDTO +import org.luxons.sevenwonders.model.boards.Board +import org.luxons.sevenwonders.model.boards.RelativeBoardPosition import org.luxons.sevenwonders.model.cards.HandCard import org.luxons.sevenwonders.ui.components.GlobalStyles import org.luxons.sevenwonders.ui.redux.* @@ -52,13 +52,21 @@ private class GameScene(props: GameSceneProps) : RComponent<GameSceneProps, RSta } private fun RBuilder.turnInfoScene(turnInfo: PlayerTurnInfo) { - val board = turnInfo.table.boards[turnInfo.playerIndex] + val board = turnInfo.getOwnBoard() + val leftBoard = turnInfo.getBoard(RelativeBoardPosition.LEFT) + val rightBoard = turnInfo.getBoard(RelativeBoardPosition.RIGHT) + val topBoards = (turnInfo.table.boards - board - leftBoard - rightBoard).reversed() div { turnInfo.scoreBoard?.let { scoreTableOverlay(it, props.players, props.leaveGame) } actionInfo(turnInfo.message) boardComponent(board = board) + leftPlayerBoardSummary(leftBoard) + rightPlayerBoardSummary(rightBoard) + if (topBoards.isNotEmpty()) { + topPlayerBoardsSummaries(topBoards) + } handRotationIndicator(turnInfo.table.handRotationDirection) val hand = turnInfo.hand if (hand != null) { @@ -97,6 +105,52 @@ private class GameScene(props: GameSceneProps) : RComponent<GameSceneProps, RSta } } + private fun RBuilder.leftPlayerBoardSummary(board: Board) { + boardSummary(props.players[board.playerIndex], board, BoardSummarySide.LEFT) { + css { + position = Position.absolute + left = 0.px + bottom = 40.pct + borderTopRightRadius = 0.4.rem + borderBottomRightRadius = 0.4.rem + } + } + } + + private fun RBuilder.rightPlayerBoardSummary(board: Board) { + boardSummary(props.players[board.playerIndex], board, BoardSummarySide.RIGHT) { + css { + position = Position.absolute + right = 0.px + bottom = 40.pct + borderTopLeftRadius = 0.4.rem + borderBottomLeftRadius = 0.4.rem + } + } + } + + private fun RBuilder.topPlayerBoardsSummaries(boards: List<Board>) { + styledDiv { + css { + position = Position.absolute + top = 0.px + left = 50.pct + transform { translate((-50).pct) } + display = Display.flex + flexDirection = FlexDirection.row + } + boards.forEach { board -> + boardSummary(props.players[board.playerIndex], board, BoardSummarySide.TOP) { + css { + borderBottomLeftRadius = 0.4.rem + borderBottomRightRadius = 0.4.rem + margin(horizontal = 2.rem) + } + } + } + } + } + private fun RBuilder.preparedMove(card: HandCard, move: PlayerMove) { bpOverlay(isOpen = true, onClose = props.unprepareMove) { preparedMove(card, move, props.unprepareMove) { diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/ProductionBar.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/ProductionBar.kt index 27a77ba6..d3243906 100644 --- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/ProductionBar.kt +++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/ProductionBar.kt @@ -12,7 +12,6 @@ import kotlinx.css.background import kotlinx.css.bottom import kotlinx.css.color import kotlinx.css.display -import kotlinx.css.fontFamily import kotlinx.css.fontSize import kotlinx.css.height import kotlinx.css.margin @@ -27,8 +26,6 @@ import kotlinx.css.vw import kotlinx.css.width import kotlinx.css.zIndex import kotlinx.html.DIV -import kotlinx.html.IMG -import kotlinx.html.title import org.luxons.sevenwonders.model.boards.Production import org.luxons.sevenwonders.model.resources.CountedResource import org.luxons.sevenwonders.model.resources.ResourceType @@ -37,7 +34,6 @@ import react.dom.* import styled.StyledDOMBuilder import styled.css import styled.styledDiv -import styled.styledImg import styled.styledSpan fun RBuilder.productionBar(gold: Int, production: Production) { @@ -51,10 +47,6 @@ fun RBuilder.productionBar(gold: Int, production: Production) { } } -private fun RBuilder.goldIndicator(amount: Int) { - tokenWithCount(tokenName = "coin", count = amount) -} - private fun RBuilder.fixedResources(resources: List<CountedResource>) { styledDiv { css { @@ -106,32 +98,6 @@ private fun RBuilder.resourceChoice(types: Set<ResourceType>, block: StyledDOMBu } } -private fun RBuilder.tokenWithCount(tokenName: String, count: Int, block: StyledDOMBuilder<DIV>.() -> Unit = {}) { - styledDiv { - block() - tokenImage(tokenName) - styledSpan { - css { tokenCountStyle() } - + "× $count" - } - } -} - -private fun RBuilder.tokenImage(tokenName: String, block: StyledDOMBuilder<IMG>.() -> Unit = {}) { - styledImg(src = getTokenImagePath(tokenName)) { - css { - tokenImageStyle() - } - attrs { - this.title = tokenName - this.alt = tokenName - } - block() - } -} - -private fun getTokenImagePath(tokenName: String) = "/images/tokens/$tokenName.png" - private fun getResourceTokenName(resourceType: ResourceType) = "resources/${resourceType.toString().toLowerCase()}" private fun CSSBuilder.productionBarStyle() { @@ -154,16 +120,3 @@ private fun CSSBuilder.choiceSeparatorStyle() { color = Color("#c29929") declarations["text-shadow"] = "0 0 1px black" } - -private fun CSSBuilder.tokenImageStyle() { - height = 3.rem - width = 3.rem - verticalAlign = VerticalAlign.middle -} - -private fun CSSBuilder.tokenCountStyle() { - fontFamily = "fantasy" - fontSize = 1.5.rem - verticalAlign = VerticalAlign.middle - marginLeft = 0.2.rem -} diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Tokens.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Tokens.kt new file mode 100644 index 00000000..e9425e0a --- /dev/null +++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Tokens.kt @@ -0,0 +1,113 @@ +package org.luxons.sevenwonders.ui.components.game + +import kotlinx.css.* +import kotlinx.html.DIV +import kotlinx.html.IMG +import kotlinx.html.title +import org.luxons.sevenwonders.ui.components.GlobalStyles +import react.RBuilder +import styled.* + +enum class TokenCountPosition { + LEFT, RIGHT, OVER +} + +fun RBuilder.goldIndicator( + amount: Int, + amountPosition: TokenCountPosition = TokenCountPosition.OVER, + imgSize: LinearDimension = 3.rem +) { + tokenWithCount( + tokenName = "coin", + title = "$amount gold coins", + imgSize = imgSize, + count = amount, + countPosition = amountPosition + ) +} + +fun RBuilder.tokenWithCount( + tokenName: String, + count: Int, + title: String = tokenName, + imgSize: LinearDimension = 3.rem, + countPosition: TokenCountPosition = TokenCountPosition.RIGHT, + brightText: Boolean = false, + block: StyledDOMBuilder<DIV>.() -> Unit = {} +) { + styledDiv { + block() + val tokenCountSize = imgSize * 0.6 + when (countPosition) { + TokenCountPosition.RIGHT -> { + tokenImage(tokenName, title = title, size = imgSize) + styledSpan { + css { + tokenCountStyle(tokenCountSize, brightText) + marginLeft = 0.2.rem + } + +"× $count" + } + } + TokenCountPosition.LEFT -> { + styledSpan { + css { + tokenCountStyle(tokenCountSize, brightText) + marginRight = 0.2.rem + } + +"$count ×" + } + tokenImage(tokenName, title = title, size = imgSize) + } + TokenCountPosition.OVER -> { + styledDiv { + css { position = Position.relative } + tokenImage(tokenName, title = title, size = imgSize) + styledSpan { + css { + +GlobalStyles.centerInParent + tokenCountStyle(tokenCountSize, brightText) + } + +"$count" + } + } + } + } + } +} + +fun RBuilder.tokenImage( + tokenName: String, + title: String = tokenName, + size: LinearDimension = 3.rem, + block: StyledDOMBuilder<IMG>.() -> Unit = {} +) { + styledImg(src = getTokenImagePath(tokenName)) { + css { + tokenImageStyle(size) + } + attrs { + this.title = title + this.alt = tokenName + } + block() + } +} + +private fun getTokenImagePath(tokenName: String) = "/images/tokens/$tokenName.png" + +private fun CSSBuilder.tokenImageStyle(size: LinearDimension) { + height = size + width = size + verticalAlign = VerticalAlign.middle +} + +private fun CSSBuilder.tokenCountStyle(size: LinearDimension, brightText: Boolean) { + fontFamily = "fantasy" + fontSize = size + verticalAlign = VerticalAlign.middle + if (brightText) { + color = Color.white + } + fontWeight = FontWeight.bold +} diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/CreateGameForm.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/CreateGameForm.kt index 82e1ae1a..6b04801e 100644 --- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/CreateGameForm.kt +++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/CreateGameForm.kt @@ -52,7 +52,7 @@ private class CreateGameForm(props: CreateGameFormProps) : RComponent<CreateGame rightElement = createGameButton() ) } - playerInfo() + currentPlayerInfo() } } diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt index 62b9f7aa..a6289649 100644 --- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt +++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt @@ -2,7 +2,8 @@ package org.luxons.sevenwonders.ui.components.gameBrowser import com.palantir.blueprintjs.bpIcon import kotlinx.css.* -import org.luxons.sevenwonders.model.api.ConnectedPlayer +import org.luxons.sevenwonders.model.api.BasicPlayerInfo +import org.luxons.sevenwonders.model.api.PlayerDTO import org.luxons.sevenwonders.ui.redux.connectState import react.RBuilder import react.RComponent @@ -13,7 +14,9 @@ import styled.styledDiv import styled.styledSpan interface PlayerInfoProps : RProps { - var connectedPlayer: ConnectedPlayer? + var player: BasicPlayerInfo? + var showUsername: Boolean + var iconSize: Int } class PlayerInfoPresenter(props: PlayerInfoProps) : RComponent<PlayerInfoProps, RState>(props) { @@ -24,39 +27,70 @@ class PlayerInfoPresenter(props: PlayerInfoProps) : RComponent<PlayerInfoProps, display = Display.flex alignItems = Align.center } - props.connectedPlayer?.let { - bpIcon(name = it.icon?.name ?: "user", size = 30) - styledDiv { - css { - display = Display.flex - flexDirection = FlexDirection.column - marginLeft = 0.3.rem - } - styledSpan { - css { - fontSize = 1.rem - } - +it.displayName - } - styledSpan { - css { - marginTop = 0.1.rem - color = Color.lightGray - fontSize = 0.8.rem - } - +"(${it.username})" - } + props.player?.let { + bpIcon(name = it.icon?.name ?: "user", size = props.iconSize) + if (props.showUsername) { + playerNameWithUsername(it.displayName, it.username) + } else { + playerName(it.displayName) } } } } + + private fun RBuilder.playerName(displayName: String) { + styledSpan { + css { + fontSize = 1.rem + marginLeft = 0.4.rem + } + +displayName + } + } + + private fun RBuilder.playerNameWithUsername(displayName: String, username: String) { + styledDiv { + css { + display = Display.flex + flexDirection = FlexDirection.column + marginLeft = 0.4.rem + } + styledSpan { + css { + fontSize = 1.rem + } + +displayName + } + styledSpan { + css { + marginTop = 0.1.rem + color = Color.lightGray + fontSize = 0.8.rem + } + +"($username)" + } + } + } +} + +fun RBuilder.playerInfo( + playerDTO: PlayerDTO, + showUsername: Boolean = false, + iconSize: Int = 30 +) = child(PlayerInfoPresenter::class) { + attrs { + this.player = playerDTO + this.showUsername = showUsername + this.iconSize = iconSize + } } -fun RBuilder.playerInfo() = playerInfo {} +fun RBuilder.currentPlayerInfo() = playerInfo {} private val playerInfo = connectState( clazz = PlayerInfoPresenter::class, mapStateToProps = { state, _ -> - connectedPlayer = state.connectedPlayer + player = state.connectedPlayer + showUsername = true } ) |