adding backend project
will try to do rest & websocket api with http4s
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
package industries.sunshine.planningpoker
|
||||
|
||||
import scala.scalajs.js
|
||||
import scala.scalajs.js.annotation.*
|
||||
import com.raquo.laminar.api.L.{*, given}
|
||||
import industries.sunshine.planningpoker.common.Models.*
|
||||
|
||||
import org.scalajs.dom
|
||||
|
||||
// import javascriptLogo from "/javascript.svg"
|
||||
@js.native @JSImport("/javascript.svg", JSImport.Default)
|
||||
val javascriptLogo: String = js.native
|
||||
|
||||
@main
|
||||
def PlanningPokerUrgh(): Unit =
|
||||
renderOnDomContentLoaded(
|
||||
dom.document.getElementById("app"),
|
||||
Main.appElement()
|
||||
)
|
||||
|
||||
object Main {
|
||||
final case class AppState(
|
||||
myId: Option[PlayerID]
|
||||
)
|
||||
// TODO is this ok for state creation? link with auth component and use in another?
|
||||
val appStateSignal = Var(AppState(Some(RoomStateView.me.id))).signal
|
||||
|
||||
def appElement(): Element = {
|
||||
div(
|
||||
className := "w-screen h-screen flex flex-col justify-center items-center",
|
||||
div(
|
||||
className := "h-24 w-full flex flex-for justify-center items-center bg-green-200",
|
||||
p(className := "text-2xl", "Here be header"),
|
||||
),
|
||||
RoomView.renderRoom(RoomStateView.testRoom)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package industries.sunshine.planningpoker
|
||||
|
||||
import scala.scalajs.js
|
||||
import com.raquo.laminar.api.L.{*, given}
|
||||
import industries.sunshine.planningpoker.common.Models.*
|
||||
|
||||
/** Rendering of the Room state
|
||||
*/
|
||||
object RoomView {
|
||||
// TODO this will take in signal of the room observable
|
||||
// NOTE i guess "other players" would have to be in circle with 'me' as empty space in the bottom
|
||||
def renderRoom(state: RoomStateView): Element = {
|
||||
val roomStateSignal = Var(state).signal
|
||||
// i want to number other players, for the star arrangement
|
||||
val otherPlayers = roomStateSignal.map { state =>
|
||||
state.players.filterNot(_.id == state.me).zipWithIndex
|
||||
}
|
||||
|
||||
div(
|
||||
className := "w-full h-full border-4 border-amber-900 flex flex-col",
|
||||
div(
|
||||
className := "flex flex-row",
|
||||
children <-- otherPlayers.split(_._1.id) { (id, initial, playerSignal) =>
|
||||
renderPlayer(playerSignal, roomStateSignal.map(_.allowedCards.size))
|
||||
}
|
||||
),
|
||||
TableView.renderTable(roomStateSignal)
|
||||
)
|
||||
}
|
||||
|
||||
def renderPlayer(p: Signal[(Player, Int)], cardsAmount: Signal[Int]): Element = {
|
||||
val xOffsetStyleSignal = p.map(_._2)
|
||||
div(
|
||||
className := "w-20 h-20 border-2 border-amber-400 m-2 absolute",
|
||||
// left <-- p.map(tuple => ((1 + tuple._2) * 10000).toString()),
|
||||
styleAttr <-- p.map(tuple => s"left: ${(1 + tuple._2) * 100}px"),
|
||||
child.text <-- p.map(_._1.name),
|
||||
renderHandCardBacks(cardsAmount)
|
||||
)
|
||||
}
|
||||
|
||||
def renderHandCardBacks(amountSignal: Signal[Int]): Element = {
|
||||
def renderCard(index: Int): Element =
|
||||
div(
|
||||
className := "w-4 h-8 m-1 rounded bg-gray-600 text-yellow"
|
||||
)
|
||||
|
||||
div(
|
||||
className := "flex flex-row",
|
||||
children <-- amountSignal.map { amount => (1 to amount).map(renderCard) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package industries.sunshine.planningpoker
|
||||
|
||||
import scala.scalajs.js
|
||||
import com.raquo.laminar.api.L.{*, given}
|
||||
import scala.scalajs.js.Dynamic.{global => g}
|
||||
import industries.sunshine.planningpoker.common.Models.*
|
||||
|
||||
object TableView {
|
||||
// new plan. map to players, split by playerId, map into specific card
|
||||
// have single funciton that calculates the card from the state.
|
||||
// but, can't have map to player, because overall state is required.
|
||||
// but can i split full state into several observables by that key? i think i should be able to
|
||||
// so, it's more efficient to share an observable, than to create multiple copies...
|
||||
def renderTable(roundSignal: Signal[RoomStateView]): Element = {
|
||||
val playerIdToCardTypeSignal =
|
||||
roundSignal.combineWith(Main.appStateSignal.map(_.myId)).map((state, myIdOpt) =>
|
||||
state.players.map(p =>
|
||||
p.id -> getPlayerCardType(p.id, state.round, p.name, myIdOpt)
|
||||
)
|
||||
)
|
||||
|
||||
div(
|
||||
className := "w-full h-full border-2 border-amber-700 flex flex-row justify-center items-center bg-green-100",
|
||||
children <-- playerIdToCardTypeSignal.split(_._1) {
|
||||
(id, initial, cardTypeSignal) =>
|
||||
renderPlayerCard(cardTypeSignal.map(_._2))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
trait CardState
|
||||
case class NoCard(name: String) extends CardState
|
||||
case object CardBack extends CardState
|
||||
case class Open(value: String) extends CardState
|
||||
|
||||
def getPlayerCardType(
|
||||
id: PlayerID,
|
||||
state: RoundState,
|
||||
name: String,
|
||||
myId: Option[PlayerID]
|
||||
): CardState = {
|
||||
state match {
|
||||
case isOpen: VotingRound =>
|
||||
if (myId.forall(_ == id)) {
|
||||
isOpen.myCard.fold(NoCard(name))(vote => Open(vote))
|
||||
} else isOpen.alreadyVoted.find(_.id == id).fold(NoCard(name))(_ => CardBack)
|
||||
case isClosed: ViewingRound =>
|
||||
isClosed.votes
|
||||
.get(id)
|
||||
.fold {
|
||||
g.console.error(s"missing vote for player $name")
|
||||
Open("error")
|
||||
} { vote => Open(vote) }
|
||||
}
|
||||
}
|
||||
|
||||
def renderPlayerCard(state: Signal[CardState]): Element = {
|
||||
val cardTypeStyle = state.map {
|
||||
case NoCard(_) => "bg-green-100 text-black border-2 border-black"
|
||||
case CardBack => "bg-green-500 border-4 border-green-700"
|
||||
case Open(_) => "text-black bg-gray-50 border-black border-2"
|
||||
}
|
||||
|
||||
div(
|
||||
className := "w-20 h-40 m-1 rounded flex justify-center items-center m-3",
|
||||
className <-- cardTypeStyle,
|
||||
div(
|
||||
className := "-rotate-45 text-xl",
|
||||
child.text <-- state.map {
|
||||
case NoCard(name) => name
|
||||
case CardBack => ""
|
||||
case Open(vote) => vote
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user