Restructure styles, add finished round advance button.
This commit is contained in:
@@ -163,6 +163,14 @@ update msg model =
|
||||
, Cmd.batch [ lobbyCmd, settingsCmd ]
|
||||
)
|
||||
|
||||
UpdateToken auth ->
|
||||
let
|
||||
shared =
|
||||
model.shared
|
||||
in
|
||||
Util.modelLift (\settings -> { model | shared = { shared | settings = settings } })
|
||||
(Settings.onTokenUpdate auth shared.settings)
|
||||
|
||||
StartMsg startMsg ->
|
||||
case model.page of
|
||||
Pages.Start startModel ->
|
||||
@@ -215,7 +223,7 @@ update msg model =
|
||||
Refresh ->
|
||||
( model, Navigation.reload )
|
||||
|
||||
-- TODO: Maybe popup something here?
|
||||
-- TODO: Error? This would be an application error. It's pretty harmless though, probably not worth interrupting.
|
||||
BlockedExternalUrl ->
|
||||
( model, Cmd.none )
|
||||
|
||||
@@ -225,6 +233,9 @@ update msg model =
|
||||
NoOp ->
|
||||
( model, Cmd.none )
|
||||
|
||||
Batch messages ->
|
||||
Util.batchUpdate messages model update
|
||||
|
||||
|
||||
view : Model -> Browser.Document Msg
|
||||
view model =
|
||||
|
||||
@@ -62,8 +62,14 @@ link icon text description href =
|
||||
|
||||
{-| Render a menu to Html.
|
||||
-}
|
||||
view : Shared -> String -> WlA.XOrigin -> WlA.YOrigin -> Menu msg -> Html msg
|
||||
view shared anchorId xOrigin yOrigin menu =
|
||||
view :
|
||||
Shared
|
||||
-> String
|
||||
-> ( WlA.XOrigin, WlA.YOrigin )
|
||||
-> ( WlA.XOrigin, WlA.YOrigin )
|
||||
-> Menu msg
|
||||
-> Html msg
|
||||
view shared anchorId ( xAnchor, yAnchor ) ( xTransform, yTransform ) menu =
|
||||
Wl.popover
|
||||
(List.concat
|
||||
[ [ WlA.anchor anchorId
|
||||
@@ -73,7 +79,8 @@ view shared anchorId xOrigin yOrigin menu =
|
||||
, HtmlA.class "menu"
|
||||
, WlA.disableFocusTrap
|
||||
]
|
||||
, WlA.anchorOrigin xOrigin yOrigin
|
||||
, WlA.anchorOrigin xAnchor yAnchor
|
||||
, WlA.transformOrigin xTransform yTransform
|
||||
]
|
||||
)
|
||||
[ Wl.popoverCard [] [ Html.ul [] (menu |> List.map (menuItem shared)) ] ]
|
||||
|
||||
@@ -17,6 +17,7 @@ import Html.Events as HtmlE
|
||||
import MassiveDecks.Card as Card
|
||||
import MassiveDecks.Card.Model as Card
|
||||
import MassiveDecks.Card.Play as Play exposing (Play)
|
||||
import MassiveDecks.Components as Components
|
||||
import MassiveDecks.Game.Action as Action
|
||||
import MassiveDecks.Game.Action.Model as Action exposing (Action)
|
||||
import MassiveDecks.Game.Messages exposing (..)
|
||||
@@ -39,6 +40,7 @@ import MassiveDecks.Strings.Languages as Lang
|
||||
import MassiveDecks.User as User exposing (User)
|
||||
import MassiveDecks.Util as Util
|
||||
import MassiveDecks.Util.Html as Html
|
||||
import MassiveDecks.Util.Maybe as Maybe
|
||||
import Set
|
||||
import Task
|
||||
import Weightless as Wl
|
||||
@@ -176,6 +178,16 @@ update msg model =
|
||||
SetPlayStyles playStyles ->
|
||||
( { model | playStyles = playStyles }, Cmd.none )
|
||||
|
||||
AdvanceRound ->
|
||||
case model.nextRound of
|
||||
Just nextRound ->
|
||||
( { model | game = { game | round = Round.P nextRound }, nextRound = Nothing }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Nothing ->
|
||||
( model, Cmd.none )
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Global.Msg
|
||||
subscriptions model =
|
||||
@@ -197,7 +209,7 @@ view shared auth decks users model =
|
||||
Judging.view shared auth decks round
|
||||
|
||||
Round.C round ->
|
||||
Complete.view shared decks users round
|
||||
Complete.view shared (Maybe.isJust model.nextRound) decks users round
|
||||
|
||||
game =
|
||||
model.game
|
||||
@@ -212,33 +224,49 @@ view shared auth decks users model =
|
||||
call |> Card.viewFilled shared decks Card.Front [] parts
|
||||
|
||||
help =
|
||||
case instruction of
|
||||
Just i ->
|
||||
Html.div [ HtmlA.class "context-help" ] [ Icon.view Icon.questionCircle, i |> Lang.html shared ]
|
||||
let
|
||||
id =
|
||||
"context-help-button"
|
||||
|
||||
Nothing ->
|
||||
Html.nothing
|
||||
helpContent =
|
||||
case instruction of
|
||||
Just i ->
|
||||
[ Components.iconButton
|
||||
[ HtmlA.id id, Strings.WhatToDo |> Lang.title shared ]
|
||||
Icon.question
|
||||
, Wl.popover
|
||||
(List.concat
|
||||
[ WlA.anchorOrigin WlA.XCenter WlA.YBottom
|
||||
, WlA.transformOrigin WlA.XRight WlA.YTop
|
||||
, [ WlA.anchor id, WlA.fixed, WlA.anchorOpenEvents [ "click" ] ]
|
||||
]
|
||||
)
|
||||
[ Wl.popoverCard [] [ i |> Lang.html shared ] ]
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
[]
|
||||
in
|
||||
Html.div [ HtmlA.id "context-help" ] helpContent
|
||||
in
|
||||
Html.div [ HtmlA.id "game" ]
|
||||
[ help
|
||||
, Html.div [ HtmlA.class "card-area" ]
|
||||
[ Html.div [ HtmlA.class "play-area" ]
|
||||
[ Html.div [ HtmlA.class "cards-in-play" ] [ renderedCall ]
|
||||
, viewAction shared action
|
||||
]
|
||||
, content
|
||||
, Html.div [ HtmlA.class "scroll-top-spacer" ] []
|
||||
, Html.div [ HtmlA.class "round" ]
|
||||
[ renderedCall
|
||||
, viewAction shared action
|
||||
]
|
||||
, content
|
||||
, Html.div [ HtmlA.class "scroll-top-spacer" ] []
|
||||
|
||||
-- TODO: Hide this when at top. Waiting on native elm scroll events, as currently we'd have to ping.
|
||||
, Html.div [ HtmlA.class "scroll-top" ]
|
||||
[ Wl.button
|
||||
[ WlA.flat
|
||||
, WlA.fab
|
||||
, WlA.inverted
|
||||
, ScrollToTop |> lift |> HtmlE.onClick
|
||||
]
|
||||
[ Icon.view Icon.arrowUp ]
|
||||
-- TODO: Hide this when at top. Waiting on native elm scroll events, as currently we'd have to ping constantly.
|
||||
, Html.div [ HtmlA.class "scroll-top" ]
|
||||
[ Wl.button
|
||||
[ WlA.flat
|
||||
, WlA.fab
|
||||
, WlA.inverted
|
||||
, ScrollToTop |> lift |> HtmlE.onClick
|
||||
]
|
||||
[ Icon.view Icon.arrowUp ]
|
||||
]
|
||||
]
|
||||
|
||||
@@ -248,25 +276,29 @@ viewAction shared visible =
|
||||
Html.div [] (Action.actions |> List.map (Action.view shared visible))
|
||||
|
||||
|
||||
applyGameEvent : Events.GameEvent -> Model -> ( Model, Cmd Global.Msg )
|
||||
applyGameEvent gameEvent model =
|
||||
applyGameEvent : Lobby.Auth -> Events.GameEvent -> Model -> ( Model, Cmd Global.Msg )
|
||||
applyGameEvent auth gameEvent model =
|
||||
case gameEvent of
|
||||
Events.HandRedrawn redraw ->
|
||||
case redraw of
|
||||
Events.Player { hand } ->
|
||||
-- TODO: Impl
|
||||
( model, Cmd.none )
|
||||
Events.HandRedrawn { player, hand } ->
|
||||
let
|
||||
game =
|
||||
model.game
|
||||
|
||||
Events.Other { player } ->
|
||||
--let
|
||||
-- playerRecord =
|
||||
-- Dict.get player model.game.players
|
||||
--
|
||||
-- newPlayerRecord =
|
||||
-- Dict.insert player { playerRecord | score = playerRecord.score - lobby.config.rules.houseRules }
|
||||
--in
|
||||
-- TODO: Impl
|
||||
( model, Cmd.none )
|
||||
-- TODO: Error, if the rule isn't enabled, we are out of sync.
|
||||
cost =
|
||||
game.rules.houseRules.reboot |> Maybe.map .cost |> Maybe.withDefault 0
|
||||
|
||||
updatePlayer =
|
||||
\id -> \p -> { p | score = p.score - cost } |> Maybe.justIf (player == id) |> Maybe.withDefault p
|
||||
|
||||
-- TODO: Error, if we get a hand but the event claims another player, we are out of sync.
|
||||
newHand =
|
||||
hand |> Maybe.andThen (Maybe.justIf (player == auth.claims.uid)) |> Maybe.withDefault model.hand
|
||||
|
||||
players =
|
||||
game.players |> Dict.map updatePlayer
|
||||
in
|
||||
( { model | game = { game | players = players }, hand = newHand }, Cmd.none )
|
||||
|
||||
Events.PlayRevealed { id, play } ->
|
||||
let
|
||||
@@ -350,19 +382,13 @@ applyGameEvent gameEvent model =
|
||||
|
||||
Events.RoundStarted { id, czar, players, call, drawn } ->
|
||||
let
|
||||
oldGame =
|
||||
model.game
|
||||
|
||||
drawnAsList =
|
||||
drawn |> Maybe.withDefault []
|
||||
|
||||
( newRound, cmd ) =
|
||||
Playing.init (Round.playing id czar players call Set.empty) Round.noPick
|
||||
|
||||
game =
|
||||
{ oldGame | round = Round.P newRound }
|
||||
in
|
||||
( { model | game = game, hand = model.hand ++ drawnAsList }, cmd )
|
||||
( { model | nextRound = Just newRound, hand = model.hand ++ drawnAsList }, cmd )
|
||||
|
||||
Events.StartRevealing { plays, drawn } ->
|
||||
case model.game.round of
|
||||
|
||||
@@ -13,13 +13,26 @@ import MassiveDecks.Model exposing (..)
|
||||
import MassiveDecks.Pages.Lobby.Messages as Lobby
|
||||
import MassiveDecks.Strings as Strings exposing (MdString)
|
||||
import MassiveDecks.Strings.Languages as Lang
|
||||
import MassiveDecks.Util.Html.Attributes as HtmlA
|
||||
import Weightless.Attributes as WlA
|
||||
|
||||
|
||||
actions : List Action
|
||||
actions =
|
||||
[ Submit, TakeBack, Judge, Like ]
|
||||
[ Submit, TakeBack, Judge, Like, Advance ]
|
||||
|
||||
|
||||
{-| Style for actions that are blocking the game from continuing until they are performed.
|
||||
-}
|
||||
blocking : List (Html.Attribute msg)
|
||||
blocking =
|
||||
[ HtmlA.class "important" ]
|
||||
|
||||
|
||||
{-| Style for an action that doesn't block the game.
|
||||
-}
|
||||
normal : List (Html.Attribute msg)
|
||||
normal =
|
||||
[ WlA.inverted, WlA.outlined ]
|
||||
|
||||
|
||||
view : Shared -> Maybe Action -> Action -> Html Global.Msg
|
||||
@@ -28,16 +41,19 @@ view shared visible action =
|
||||
{ icon, attrs, title, onClick } =
|
||||
case action of
|
||||
Submit ->
|
||||
IconView Icon.check [ HtmlA.class "important" ] Strings.SubmitPlay Game.Submit
|
||||
IconView Icon.check blocking Strings.SubmitPlay Game.Submit
|
||||
|
||||
TakeBack ->
|
||||
IconView Icon.undo [ WlA.inverted, WlA.outlined ] Strings.TakeBackPlay Game.TakeBack
|
||||
IconView Icon.undo normal Strings.TakeBackPlay Game.TakeBack
|
||||
|
||||
Judge ->
|
||||
IconView Icon.trophy [ HtmlA.class "important" ] Strings.JudgePlay Game.Judge
|
||||
IconView Icon.trophy blocking Strings.JudgePlay Game.Judge
|
||||
|
||||
Like ->
|
||||
IconView Icon.thumbsUp [ WlA.inverted, WlA.outlined ] Strings.LikePlay Game.Like
|
||||
IconView Icon.thumbsUp normal Strings.LikePlay Game.Like
|
||||
|
||||
Advance ->
|
||||
IconView Icon.forward normal Strings.AdvanceRound Game.AdvanceRound
|
||||
in
|
||||
Components.floatingActionButton
|
||||
(List.concat
|
||||
|
||||
@@ -6,3 +6,4 @@ type Action
|
||||
| TakeBack
|
||||
| Judge
|
||||
| Like
|
||||
| Advance
|
||||
|
||||
@@ -15,3 +15,4 @@ type Msg
|
||||
| Like
|
||||
| ScrollToTop
|
||||
| SetPlayStyles PlayStyles
|
||||
| AdvanceRound
|
||||
|
||||
@@ -25,6 +25,7 @@ type alias Model =
|
||||
{ game : Game
|
||||
, hand : List Card.Response
|
||||
, playStyles : PlayStyles
|
||||
, nextRound : Maybe Round.Playing
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +36,7 @@ emptyModel game =
|
||||
{ game = game
|
||||
, hand = []
|
||||
, playStyles = Dict.empty
|
||||
, nextRound = Nothing
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import Html.Attributes as HtmlA
|
||||
import Html.Keyed as HtmlK
|
||||
import MassiveDecks.Card as Card
|
||||
import MassiveDecks.Card.Model as Card
|
||||
import MassiveDecks.Game.Action.Model as Action
|
||||
import MassiveDecks.Game.Model exposing (..)
|
||||
import MassiveDecks.Game.Round as Round
|
||||
import MassiveDecks.Messages as Global
|
||||
@@ -20,16 +21,16 @@ import MassiveDecks.Util.Html as Html
|
||||
import MassiveDecks.Util.Maybe as Maybe
|
||||
|
||||
|
||||
view : Shared -> List Configure.Deck -> Dict User.Id User -> Round.Complete -> RoundView Global.Msg
|
||||
view shared decks users round =
|
||||
view : Shared -> Bool -> List Configure.Deck -> Dict User.Id User -> Round.Complete -> RoundView Global.Msg
|
||||
view shared nextRoundReady decks users round =
|
||||
let
|
||||
winning =
|
||||
round.plays |> Dict.get round.winner
|
||||
in
|
||||
{ instruction = Nothing
|
||||
, action = Nothing
|
||||
{ instruction = Strings.AdvanceRoundInstruction |> Maybe.justIf nextRoundReady
|
||||
, action = Action.Advance |> Maybe.justIf nextRoundReady
|
||||
, content =
|
||||
HtmlK.ul [ HtmlA.class "judging plays" ]
|
||||
HtmlK.ul [ HtmlA.class "complete plays cards" ]
|
||||
(round.plays |> Dict.toList |> List.map (viewPlay shared decks users round.winner))
|
||||
, fillCallWith = winning |> Maybe.withDefault []
|
||||
}
|
||||
@@ -45,7 +46,7 @@ viewPlay :
|
||||
viewPlay shared decks users winner ( id, responses ) =
|
||||
let
|
||||
cards =
|
||||
responses |> List.map (\r -> Card.view shared decks Card.Front [] (Card.R r))
|
||||
responses |> List.map (\r -> ( r.details.id, Card.view shared decks Card.Front [] (Card.R r) ))
|
||||
|
||||
playedBy =
|
||||
users |> Dict.get id |> Maybe.map .name |> Maybe.withDefault (Strings.UnknownUser |> Lang.string shared)
|
||||
@@ -58,6 +59,6 @@ viewPlay shared decks users winner ( id, responses ) =
|
||||
( id
|
||||
, Html.li [ HtmlA.class "play-with-byline" ]
|
||||
[ Html.span [ HtmlA.class "byline" ] byline
|
||||
, Html.div [ HtmlA.class "play" ] cards
|
||||
, HtmlK.ol [ HtmlA.class "play card-set" ] cards
|
||||
]
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ import Dict exposing (Dict)
|
||||
import Html exposing (Html)
|
||||
import Html.Attributes as HtmlA
|
||||
import Html.Events as HtmlE
|
||||
import Html.Keyed as HtmlK
|
||||
import MassiveDecks.Card as Card
|
||||
import MassiveDecks.Card.Model as Card
|
||||
import MassiveDecks.Game.Action.Model as Action
|
||||
@@ -66,7 +67,7 @@ view shared auth decks model round =
|
||||
( Just Action.TakeBack, Strings.WaitingForPlaysInstruction, True )
|
||||
|
||||
hand =
|
||||
Html.div [ HtmlA.classList [ ( "hand", True ), ( "not-playing", notPlaying ) ] ]
|
||||
HtmlK.ul [ HtmlA.classList [ ( "hand", True ), ( "cards", True ), ( "not-playing", notPlaying ) ] ]
|
||||
(model.hand |> List.map (round.pick.cards |> viewHandCard shared decks))
|
||||
|
||||
backgroundPlays =
|
||||
@@ -93,9 +94,10 @@ view shared auth decks model round =
|
||||
{- Private -}
|
||||
|
||||
|
||||
viewHandCard : Shared -> List Configure.Deck -> List Card.Id -> Card.Response -> Html Global.Msg
|
||||
viewHandCard : Shared -> List Configure.Deck -> List Card.Id -> Card.Response -> ( String, Html Global.Msg )
|
||||
viewHandCard shared decks picked response =
|
||||
Card.view
|
||||
( response.details.id
|
||||
, Card.view
|
||||
shared
|
||||
decks
|
||||
Card.Front
|
||||
@@ -103,6 +105,7 @@ viewHandCard shared decks picked response =
|
||||
, response.details.id |> Game.Pick |> lift |> HtmlE.onClick
|
||||
]
|
||||
(Card.R response)
|
||||
)
|
||||
|
||||
|
||||
viewBackgroundPlay : PlayStyles -> Int -> Set User.Id -> User.Id -> Html msg
|
||||
|
||||
@@ -22,7 +22,7 @@ type alias Details msg =
|
||||
-}
|
||||
view : String -> Maybe Play.Id -> List (Details msg) -> Html msg
|
||||
view class picked details =
|
||||
HtmlK.ul [ HtmlA.classList [ ( class, True ), ( "plays", True ) ] ] (details |> List.map (viewPlay picked))
|
||||
HtmlK.ul [ HtmlA.classList [ ( class, True ), ( "cards", True ), ( "plays", True ) ] ] (details |> List.map (viewPlay picked))
|
||||
|
||||
|
||||
|
||||
@@ -32,13 +32,12 @@ view class picked details =
|
||||
viewPlay : Maybe Play.Id -> Details msg -> ( String, Html msg )
|
||||
viewPlay picked { id, responses, action, attrs } =
|
||||
( id
|
||||
, Html.li
|
||||
(List.concat
|
||||
[ [ HtmlA.classList [ ( "play", True ), ( "picked", picked == Just id ) ]
|
||||
, action |> Maybe.map HtmlE.onClick |> Maybe.withDefault HtmlA.nothing
|
||||
]
|
||||
, attrs
|
||||
]
|
||||
)
|
||||
(responses |> List.map (\card -> Html.div [ HtmlA.class "overlap" ] [ card ]))
|
||||
, Html.li []
|
||||
[ Html.ol
|
||||
(HtmlA.classList [ ( "play", True ), ( "card-set", True ), ( "picked", picked == Just id ) ]
|
||||
:: (action |> Maybe.map HtmlE.onClick |> Maybe.withDefault HtmlA.nothing)
|
||||
:: attrs
|
||||
)
|
||||
(responses |> List.map (\card -> Html.li [] [ card ]))
|
||||
]
|
||||
)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
module MassiveDecks.Icon exposing
|
||||
( callCard
|
||||
, massiveDecks
|
||||
, minimalCardSize
|
||||
, rereadGames
|
||||
, responseCard
|
||||
, squareCardSize
|
||||
)
|
||||
|
||||
{-| Icons that aren't in FontAwesome that we need.
|
||||
-}
|
||||
|
||||
import FontAwesome.Icon as Icon exposing (Icon)
|
||||
|
||||
|
||||
rereadGames : Icon
|
||||
rereadGames =
|
||||
Icon "fab" "reread-games" 512 512 "M258 16c-62 0-124 24-171 71-95 94-94 246 0 339 95 93 250 93 345 0l12-12-15-14-12 12-10-10c-82 80-213 80-295 0-82-81-82-210-1-291 81-80 212-81 294-3l-38 35 129 25-1-3-26-117-39 36c-48-46-110-68-172-68zm-79 159c-46 1-70 10-70 10v133s24-9 70-9c50 0 70 20 70 20V196s-20-21-70-21zm160 0c-50 0-70 21-70 21v133s20-20 70-20c46 0 70 9 70 9V185s-24-9-70-10zM179 323c-46 1-70 10-70 10v16s24-9 70-9c50 0 81 31 81 31s30-31 80-31c46 0 70 9 70 9v-16s-24-9-70-10c-50 0-80 32-80 32s-31-32-81-32z"
|
||||
|
||||
|
||||
massiveDecks : Icon
|
||||
massiveDecks =
|
||||
Icon "fab" "massive-decks" 512 512 "M273 20c-11 0-21 9-23 21l-9 88h-8L39 163c-12 2-21 15-19 27l50 283c2 12 15 21 27 19l194-34c12-3 21-15 18-27l-13-73 140 14c13 2 25-8 26-20l30-286c1-13-8-24-21-25L276 20h-3zm0 16h1l196 21c4 0 6 3 6 7l-30 286c0 4-4 7-8 6l-144-15-35-193-3-9 10-97c1-3 4-6 7-6zm47 106l-10 99 39 4c15 2 25 0 32-8 9-8 15-21 16-37 2-15-1-29-8-39-6-9-15-13-30-15zm19 20l18 1c16 2 22 14 20 35-3 22-11 32-27 31l-18-2zm-135 91l17 98-20 4-13-77-4 80-20 3-32-73 14 76-20 4-18-98 31-6 31 75 4-81z"
|
||||
|
||||
|
||||
minimalCardSize : Icon
|
||||
minimalCardSize =
|
||||
Icon "fas" "minimal-card-size" 384 512 "M45 395c-21 0-39 17-39 39v39c0 21 18 39 39 39h294c21 0 39-18 39-39v-39c0-22-18-39-39-39z"
|
||||
|
||||
|
||||
squareCardSize : Icon
|
||||
squareCardSize =
|
||||
Icon "fas" "square-card-size" 384 512 "M45 141c-21 0-39 17-39 39v293c0 21 18 39 39 39h294c21 0 39-18 39-39V180c0-22-18-39-39-39z"
|
||||
|
||||
|
||||
callCard : Icon
|
||||
callCard =
|
||||
Icon "fas" "call-card" 384 512 "M45 10h294c16 0 29 13 29 29v434c0 16-13 29-29 29H45c-16 0-29-13-29-29V39c0-16 13-29 29-29z"
|
||||
|
||||
|
||||
responseCard : Icon
|
||||
responseCard =
|
||||
Icon "fas" "response-card" 384 512 "M45 0C24 0 6 18 6 39v434c0 21 18 39 39 39h294c21 0 39-18 39-39V39c0-21-18-39-39-39zm0 20h294c11 0 19 8 19 19v434c0 11-8 19-19 19H45c-11 0-19-8-19-19V39c0-11 8-19 19-19z"
|
||||
@@ -22,9 +22,11 @@ type Msg
|
||||
| LobbyMsg Lobby.Msg
|
||||
| SettingsMsg Settings.Msg
|
||||
| ErrorMsg Error.Msg
|
||||
| UpdateToken Lobby.Auth
|
||||
| CastStatusUpdate Cast.Status
|
||||
| TryCast Lobby.Auth
|
||||
| Refresh
|
||||
| BlockedExternalUrl
|
||||
| Copy String
|
||||
| NoOp
|
||||
| Batch (List Msg)
|
||||
|
||||
@@ -97,7 +97,12 @@ settings =
|
||||
(Json.maybe (Json.field "lastUsedName" Json.string))
|
||||
(Json.field "recentDecks" (Json.list externalSource))
|
||||
(Json.maybe (Json.field "chosenLanguage" language))
|
||||
(Json.field "compactCards" Json.bool)
|
||||
(Json.field "compactCards" cardSize)
|
||||
|
||||
|
||||
cardSize : Json.Decoder Settings.CardSize
|
||||
cardSize =
|
||||
Json.int |> Json.andThen (\i -> i |> Settings.cardSizeFromValue |> Maybe.map Json.succeed |> Maybe.withDefault (unknownValue "card size" (String.fromInt i)))
|
||||
|
||||
|
||||
gameCode : Json.Decoder GameCode
|
||||
@@ -463,10 +468,31 @@ eventByName name =
|
||||
"RoundFinished" ->
|
||||
gameEvent roundFinished
|
||||
|
||||
"HandRedrawn" ->
|
||||
gameEvent handRedrawn
|
||||
|
||||
"PrivilegeSet" ->
|
||||
privilegeSet
|
||||
|
||||
_ ->
|
||||
unknownValue "event" name
|
||||
|
||||
|
||||
privilegeSet : Json.Decoder Events.Event
|
||||
privilegeSet =
|
||||
Json.map3 (\u -> \p -> \t -> Events.PrivilegeSet { user = u, privilege = p, token = t })
|
||||
(Json.field "user" userId)
|
||||
(Json.field "privilege" privilege)
|
||||
(Json.maybe (Json.field "token" lobbyToken))
|
||||
|
||||
|
||||
handRedrawn : Json.Decoder Events.GameEvent
|
||||
handRedrawn =
|
||||
Json.map2 (\pl -> \ha -> Events.HandRedrawn { player = pl, hand = ha })
|
||||
(Json.field "player" userId)
|
||||
(Json.maybe (Json.field "hand" (Json.list response)))
|
||||
|
||||
|
||||
roundFinished : Json.Decoder Events.GameEvent
|
||||
roundFinished =
|
||||
Json.map2 (\wi -> \pb -> Events.RoundFinished { winner = wi, playedBy = pb })
|
||||
|
||||
@@ -43,7 +43,7 @@ settings s =
|
||||
[ [ ( "tokens", s.tokens |> Dict.toList |> List.map (\( gc, t ) -> ( gc, Json.string t )) |> Json.object )
|
||||
, ( "openUserList", Json.bool s.openUserList )
|
||||
, ( "recentDecks", Json.list source s.recentDecks )
|
||||
, ( "compactCards", Json.bool s.compactCards )
|
||||
, ( "compactCards", s.cardSize |> cardSize )
|
||||
]
|
||||
, lun
|
||||
, cl
|
||||
@@ -52,6 +52,11 @@ settings s =
|
||||
Json.object fields
|
||||
|
||||
|
||||
cardSize : Settings.CardSize -> Json.Value
|
||||
cardSize =
|
||||
Settings.cardSizeToValue >> Json.int
|
||||
|
||||
|
||||
lobbyCreation : Start.LobbyCreation -> Json.Value
|
||||
lobbyCreation c =
|
||||
Json.object
|
||||
|
||||
@@ -40,17 +40,21 @@ import MassiveDecks.Pages.Lobby.Invite as Invite
|
||||
import MassiveDecks.Pages.Lobby.Messages exposing (..)
|
||||
import MassiveDecks.Pages.Lobby.Model exposing (..)
|
||||
import MassiveDecks.Pages.Lobby.Route exposing (..)
|
||||
import MassiveDecks.Pages.Lobby.Token as Token
|
||||
import MassiveDecks.Pages.Route as Route
|
||||
import MassiveDecks.Pages.Start.Route as Start
|
||||
import MassiveDecks.ServerConnection as ServerConnection
|
||||
import MassiveDecks.Settings as Settings
|
||||
import MassiveDecks.Settings.Messages as Settings
|
||||
import MassiveDecks.Settings.Model as Settings
|
||||
import MassiveDecks.Strings as Strings exposing (MdString)
|
||||
import MassiveDecks.Strings.Languages as Lang
|
||||
import MassiveDecks.User as User exposing (User)
|
||||
import MassiveDecks.Util as Util
|
||||
import MassiveDecks.Util.Html as Html
|
||||
import MassiveDecks.Util.Html.Attributes as HtmlA
|
||||
import MassiveDecks.Util.Maybe as Maybe
|
||||
import MassiveDecks.Util.Result as Result
|
||||
import Weightless as Wl
|
||||
import Weightless.Attributes as WlA
|
||||
|
||||
@@ -99,7 +103,7 @@ subscriptions model =
|
||||
[ model.lobby |> Maybe.andThen .game |> Maybe.map Game.subscriptions |> Maybe.withDefault Sub.none
|
||||
, model.notifications |> Animated.subscriptions |> Sub.map (NotificationMsg >> Global.LobbyMsg)
|
||||
, ServerConnection.notifications
|
||||
(EventReceived >> Global.LobbyMsg)
|
||||
eventPreprocess
|
||||
(ErrorReceived >> Global.LobbyMsg)
|
||||
(Error.Json >> Error.Add >> Global.ErrorMsg)
|
||||
]
|
||||
@@ -149,7 +153,7 @@ update msg model =
|
||||
(\game ->
|
||||
Util.modelLift
|
||||
(\g -> { model | lobby = Just { lobby | game = Just g } })
|
||||
(Game.applyGameEvent gameEvent game)
|
||||
(Game.applyGameEvent model.auth gameEvent game)
|
||||
)
|
||||
|> Maybe.withDefault ( model, Cmd.none )
|
||||
|
||||
@@ -193,6 +197,16 @@ update msg model =
|
||||
in
|
||||
addNotification message { model | lobby = Just { lobby | users = newUsers } }
|
||||
|
||||
Events.PrivilegeSet { user, privilege } ->
|
||||
let
|
||||
updateUser =
|
||||
\id -> \u -> { u | privilege = privilege } |> Maybe.justIf (user == id) |> Maybe.withDefault u
|
||||
|
||||
users =
|
||||
lobby.users |> Dict.map updateUser
|
||||
in
|
||||
( { model | lobby = Just { lobby | users = users } }, Cmd.none )
|
||||
|
||||
Nothing ->
|
||||
case event of
|
||||
Events.Sync { state, hand, play } ->
|
||||
@@ -260,21 +274,15 @@ view shared model =
|
||||
else
|
||||
Icon.users
|
||||
|
||||
title =
|
||||
model.lobby
|
||||
|> Maybe.andThen .game
|
||||
|> Maybe.map (.game >> .round >> Round.data >> .call >> .body >> Parts.viewSingleLine)
|
||||
|
||||
notifications =
|
||||
model.notifications |> List.map (keyedViewNotification shared model.lobby)
|
||||
in
|
||||
[ Html.div
|
||||
[ HtmlA.classList
|
||||
[ ( "lobby", True )
|
||||
, ( "compact-cards", shared.settings.settings.compactCards )
|
||||
]
|
||||
[ HtmlA.id "lobby"
|
||||
, HtmlA.classList [ ( "collapsed-users", not usersShown ) ]
|
||||
, shared.settings.settings.cardSize |> cardSizeToAttr
|
||||
]
|
||||
[ Html.div [ HtmlA.id "top-bar" ]
|
||||
(Html.div [ HtmlA.id "top-bar" ]
|
||||
[ Html.div [ HtmlA.class "left" ]
|
||||
(List.concat
|
||||
[ [ Components.iconButtonStyled
|
||||
@@ -282,22 +290,22 @@ view shared model =
|
||||
, Strings.ToggleUserList |> Lang.title shared
|
||||
]
|
||||
( [ Icon.lg ], usersIcon )
|
||||
, gameMenu shared
|
||||
, lobbyMenu shared model.auth
|
||||
]
|
||||
, castButton
|
||||
]
|
||||
)
|
||||
, title |> Maybe.map (Html.div [ HtmlA.class "title-call" ]) |> Maybe.withDefault Html.nothing
|
||||
, Html.div [] [ Settings.view shared ]
|
||||
]
|
||||
, model.lobby
|
||||
|> Maybe.map (viewLobby shared model.configure usersShown model.auth model.selectedUser)
|
||||
|> Maybe.withDefault
|
||||
(Html.div [ HtmlA.class "loading" ]
|
||||
[ Icon.viewStyled [ Icon.spin, Icon.fa3x ] Icon.circleNotch ]
|
||||
)
|
||||
, HtmlK.ol [ HtmlA.class "notifications" ] notifications
|
||||
]
|
||||
:: HtmlK.ol [ HtmlA.class "notifications" ] notifications
|
||||
:: (model.lobby
|
||||
|> Maybe.map (viewLobby shared model.configure model.auth model.selectedUser)
|
||||
|> Maybe.withDefault
|
||||
[ Html.div [ HtmlA.class "loading" ]
|
||||
[ Icon.viewStyled [ Icon.spin, Icon.fa3x ] Icon.circleNotch ]
|
||||
]
|
||||
)
|
||||
)
|
||||
, Invite.dialog shared
|
||||
model.auth.claims.gc
|
||||
(model.lobby |> Maybe.andThen (.config >> .password))
|
||||
@@ -309,26 +317,71 @@ view shared model =
|
||||
{- Private -}
|
||||
|
||||
|
||||
gameMenu : Shared -> Html Global.Msg
|
||||
gameMenu shared =
|
||||
cardSizeToAttr : Settings.CardSize -> Html.Attribute msg
|
||||
cardSizeToAttr cardSize =
|
||||
case cardSize of
|
||||
Settings.Minimal ->
|
||||
HtmlA.class "minimal-card-size"
|
||||
|
||||
Settings.Square ->
|
||||
HtmlA.class "square-card-size"
|
||||
|
||||
Settings.Full ->
|
||||
HtmlA.nothing
|
||||
|
||||
|
||||
eventPreprocess : Events.Event -> Global.Msg
|
||||
eventPreprocess event =
|
||||
case event of
|
||||
Events.PrivilegeSet { token } ->
|
||||
Global.Batch
|
||||
[ token
|
||||
|> Maybe.map (Token.decode >> Result.unifiedMap (Error.Token >> Error.Add >> Global.ErrorMsg) Global.UpdateToken)
|
||||
|> Maybe.withDefault Global.NoOp
|
||||
, event |> EventReceived |> Global.LobbyMsg
|
||||
]
|
||||
|
||||
_ ->
|
||||
event |> EventReceived |> Global.LobbyMsg
|
||||
|
||||
|
||||
lobbyMenu : Shared -> Auth -> Html Global.Msg
|
||||
lobbyMenu shared auth =
|
||||
let
|
||||
id =
|
||||
"game-menu-button"
|
||||
"lobby-menu-button"
|
||||
|
||||
menuItems =
|
||||
[ Menu.button Icon.bullhorn Strings.InvitePlayers Strings.InvitePlayers (ToggleInviteDialog |> Global.LobbyMsg |> Just)
|
||||
, Menu.Separator
|
||||
, Menu.button Icon.userClock Strings.SetAway Strings.SetAway Nothing
|
||||
lobbyMenuItems =
|
||||
[ Menu.button Icon.bullhorn Strings.InvitePlayers Strings.InvitePlayers (ToggleInviteDialog |> Global.LobbyMsg |> Just) ]
|
||||
|
||||
userLobbyMenuItems =
|
||||
[ Menu.button Icon.userClock Strings.SetAway Strings.SetAway Nothing
|
||||
, Menu.button Icon.signOutAlt Strings.LeaveGame Strings.LeaveGame Nothing
|
||||
, Menu.Separator
|
||||
, Menu.link Icon.info Strings.AboutTheGame Strings.AboutTheGame (Just "https://github.com/lattyware/massivedecks")
|
||||
]
|
||||
|
||||
privilegedLobbyMenuItems =
|
||||
[ Menu.button Icon.stopCircle Strings.EndGame Strings.EndGameDescription Nothing
|
||||
]
|
||||
|
||||
mdMenuItems =
|
||||
[ Menu.link Icon.info Strings.AboutTheGame Strings.AboutTheGame (Just "https://github.com/lattyware/massivedecks")
|
||||
, Menu.link Icon.bug Strings.ReportError Strings.ReportError (Just "https://github.com/Lattyware/massivedecks/issues/new")
|
||||
]
|
||||
|
||||
menuItems =
|
||||
[ lobbyMenuItems |> Just
|
||||
, userLobbyMenuItems |> Just
|
||||
, privilegedLobbyMenuItems |> Maybe.justIf (auth.claims.pvg == User.Privileged)
|
||||
, mdMenuItems |> Just
|
||||
]
|
||||
|
||||
separatedMenuItems =
|
||||
menuItems |> List.filterMap identity |> List.intersperse [ Menu.Separator ] |> List.concat
|
||||
in
|
||||
Html.div []
|
||||
[ Components.iconButtonStyled [ HtmlA.id id, Strings.GameMenu |> Lang.title shared ]
|
||||
( [ Icon.lg ], Icon.bars )
|
||||
, Menu.view shared id WlA.XCenter WlA.YBottom menuItems
|
||||
, Menu.view shared id ( WlA.XCenter, WlA.YBottom ) ( WlA.XLeft, WlA.YTop ) separatedMenuItems
|
||||
]
|
||||
|
||||
|
||||
@@ -447,30 +500,29 @@ username shared users id =
|
||||
|> Maybe.withDefault (Strings.UnknownUser |> Lang.string shared)
|
||||
|
||||
|
||||
viewLobby : Shared -> Configure.Model -> Bool -> Auth -> Maybe User.Id -> Lobby -> Html Global.Msg
|
||||
viewLobby shared configure usersShown auth selectedUser lobby =
|
||||
viewLobby : Shared -> Configure.Model -> Auth -> Maybe User.Id -> Lobby -> List (Html Global.Msg)
|
||||
viewLobby shared configure auth selectedUser lobby =
|
||||
let
|
||||
game =
|
||||
lobby.game |> Maybe.map .game
|
||||
|
||||
privileged =
|
||||
auth.claims.pvg == User.Privileged
|
||||
|
||||
content =
|
||||
[ viewUsers shared auth.claims.uid selectedUser lobby.users game
|
||||
, Html.div [ HtmlA.id "scroll-frame" ]
|
||||
[ lobby.game
|
||||
|> Maybe.map (Game.view shared auth lobby.config.decks lobby.users)
|
||||
|> Maybe.withDefault (Configure.view shared privileged configure auth.claims.gc lobby lobby.config)
|
||||
]
|
||||
]
|
||||
in
|
||||
Html.div [ HtmlA.classList [ ( "content-wrapper", True ), ( "collapsed-users", not usersShown ) ] ] content
|
||||
[ Html.div [ HtmlA.id "lobby-content" ]
|
||||
[ viewUsers shared auth.claims.uid selectedUser lobby.users game
|
||||
, Html.div [ HtmlA.id "scroll-frame" ]
|
||||
[ lobby.game
|
||||
|> Maybe.map (Game.view shared auth lobby.config.decks lobby.users)
|
||||
|> Maybe.withDefault (Configure.view shared privileged configure auth.claims.gc lobby lobby.config)
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
viewUsers : Shared -> User.Id -> Maybe User.Id -> Dict User.Id User -> Maybe Game -> Html Global.Msg
|
||||
viewUsers shared player selectedUser users game =
|
||||
Wl.card [ HtmlA.class "users" ]
|
||||
Wl.card [ HtmlA.id "users" ]
|
||||
[ Html.div [ HtmlA.class "collapsible" ]
|
||||
[ users
|
||||
|> Dict.toList
|
||||
@@ -533,7 +585,7 @@ viewUser shared player selectedUser game ( userId, user ) =
|
||||
)
|
||||
, Html.span [ WlA.listItemSlot WlA.AfterItem ] score
|
||||
]
|
||||
, Menu.view shared id WlA.XRight WlA.YTop menuItems
|
||||
, Menu.view shared id ( WlA.XRight, WlA.YCenter ) ( WlA.XLeft, WlA.YCenter ) menuItems
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ module MassiveDecks.Pages.Lobby.Actions exposing
|
||||
( addDeck
|
||||
, changeHouseRule
|
||||
, judge
|
||||
, redraw
|
||||
, removeDeck
|
||||
, reveal
|
||||
, setHandSize
|
||||
@@ -82,6 +83,11 @@ judge play =
|
||||
action "Judge" [ ( "winner", play |> Json.string ) ]
|
||||
|
||||
|
||||
redraw : Cmd msg
|
||||
redraw =
|
||||
action "Redraw" []
|
||||
|
||||
|
||||
|
||||
{- Private -}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ module MassiveDecks.Pages.Lobby.Events exposing
|
||||
, Event(..)
|
||||
, GameEvent(..)
|
||||
, PresenceState(..)
|
||||
, Redraw(..)
|
||||
)
|
||||
|
||||
import Dict exposing (Dict)
|
||||
@@ -28,6 +27,7 @@ type Event
|
||||
-- Not a game event because we don't need to be in a game
|
||||
| GameStarted { round : Round.Playing, hand : List Card.Response }
|
||||
| Game GameEvent
|
||||
| PrivilegeSet { user : User.Id, privilege : User.Privilege, token : Maybe Lobby.Token }
|
||||
|
||||
|
||||
{-| The user's intentional presence in the lobby.
|
||||
@@ -53,13 +53,8 @@ type DeckChange
|
||||
| Fail { reason : Source.LoadFailureReason }
|
||||
|
||||
|
||||
type Redraw
|
||||
= Player { hand : List Card.Response }
|
||||
| Other { player : User.Id }
|
||||
|
||||
|
||||
type GameEvent
|
||||
= HandRedrawn Redraw
|
||||
= HandRedrawn { player : User.Id, hand : Maybe (List Card.Response) }
|
||||
| PlayRevealed { id : Play.Id, play : List Card.Response }
|
||||
| PlaySubmitted { by : User.Id }
|
||||
| PlayTakenBack { by : User.Id }
|
||||
|
||||
@@ -21,6 +21,7 @@ import MassiveDecks.Card.Source.Model as Source
|
||||
import MassiveDecks.Components.Form as Form
|
||||
import MassiveDecks.Components.Form.Message as Message
|
||||
import MassiveDecks.Error as Error
|
||||
import MassiveDecks.Icon as Icon
|
||||
import MassiveDecks.Messages as Global
|
||||
import MassiveDecks.Model exposing (..)
|
||||
import MassiveDecks.Models.MdError as MdError exposing (MdError)
|
||||
@@ -43,7 +44,6 @@ import MassiveDecks.Util as Util
|
||||
import MassiveDecks.Util.Html as Html
|
||||
import MassiveDecks.Util.Maybe as Maybe
|
||||
import MassiveDecks.Version as Version
|
||||
import Reread
|
||||
import Svg.Attributes as SvgA
|
||||
import Weightless as Wl
|
||||
import Weightless.Attributes as WlA
|
||||
@@ -169,13 +169,13 @@ view shared model =
|
||||
, Strings.MDProject |> Lang.title shared
|
||||
, HtmlA.href "https://github.com/Lattyware/massivedecks"
|
||||
]
|
||||
[ Icon.viewStyled [ Strings.MDLogoDescription |> Lang.alt shared ] Reread.mdIcon ]
|
||||
[ Icon.viewStyled [ Strings.MDLogoDescription |> Lang.alt shared ] Icon.massiveDecks ]
|
||||
, Html.blankA
|
||||
[ HtmlA.class "logo"
|
||||
, Strings.DevelopedByReread |> Lang.title shared
|
||||
, HtmlA.href "https://www.rereadgames.com/"
|
||||
]
|
||||
[ Icon.viewStyled [ Strings.RereadLogoDescription |> Lang.alt shared ] Reread.icon ]
|
||||
[ Icon.viewStyled [ Strings.RereadLogoDescription |> Lang.alt shared ] Icon.rereadGames ]
|
||||
]
|
||||
, Html.p [ HtmlA.class "version" ]
|
||||
[ Html.text "\""
|
||||
|
||||
@@ -4,7 +4,6 @@ module MassiveDecks.Pages.Start.LobbyBrowser.Model exposing
|
||||
, UserSummary
|
||||
)
|
||||
|
||||
import MassiveDecks.Error.Model exposing (Error)
|
||||
import MassiveDecks.Pages.Lobby.GameCode as GameCode exposing (GameCode)
|
||||
import MassiveDecks.Pages.Lobby.Model as Lobby
|
||||
import MassiveDecks.Requests.HttpData.Model exposing (HttpData)
|
||||
|
||||
@@ -67,7 +67,7 @@ checkAlive : (Request.Response () (Dict Lobby.Token Bool) -> msg) -> List Lobby.
|
||||
checkAlive msg tokens =
|
||||
{ method = "POST"
|
||||
, headers = []
|
||||
, url = url [ "games", "alive" ]
|
||||
, url = url [ "alive" ]
|
||||
, body = tokens |> Encoders.checkAlive |> Http.jsonBody
|
||||
, expect = Request.expectResponse msg noError Decoders.tokenValidity
|
||||
, timeout = Nothing
|
||||
|
||||
@@ -3,6 +3,7 @@ module MassiveDecks.Settings exposing
|
||||
, defaults
|
||||
, init
|
||||
, onJoinLobby
|
||||
, onTokenUpdate
|
||||
, update
|
||||
, view
|
||||
)
|
||||
@@ -19,6 +20,7 @@ import Http
|
||||
import MassiveDecks.Components as Components
|
||||
import MassiveDecks.Components.Form as Form
|
||||
import MassiveDecks.Components.Form.Message as Message
|
||||
import MassiveDecks.Icon as Icon
|
||||
import MassiveDecks.LocalStorage as LocalStorage
|
||||
import MassiveDecks.Messages as Global
|
||||
import MassiveDecks.Model exposing (..)
|
||||
@@ -34,6 +36,7 @@ import MassiveDecks.Strings.Languages as Lang
|
||||
import MassiveDecks.Strings.Languages.Model as Lang exposing (Language)
|
||||
import Weightless as Wl
|
||||
import Weightless.Attributes as WlA
|
||||
import Weightless.Slider as Slider
|
||||
|
||||
|
||||
init : Settings -> ( Model, Cmd Global.Msg )
|
||||
@@ -63,7 +66,7 @@ defaults =
|
||||
, openUserList = False
|
||||
, recentDecks = []
|
||||
, chosenLanguage = Nothing
|
||||
, compactCards = False
|
||||
, cardSize = Full
|
||||
}
|
||||
|
||||
|
||||
@@ -76,8 +79,8 @@ update msg model =
|
||||
ChangeLang language ->
|
||||
changeSettings (\s -> { s | chosenLanguage = language }) model
|
||||
|
||||
ChangeCompactCards enabled ->
|
||||
changeSettings (\s -> { s | compactCards = enabled }) model
|
||||
ChangeCardSize size ->
|
||||
changeSettings (\s -> { s | cardSize = size }) model
|
||||
|
||||
ChangeOpenUserList open ->
|
||||
changeSettings (\s -> { s | openUserList = open }) model
|
||||
@@ -117,7 +120,7 @@ view shared =
|
||||
[ Html.h3 [] [ Strings.SettingsTitle |> Lang.html shared ]
|
||||
, Html.div [ HtmlA.class "body" ]
|
||||
[ languageSelector shared
|
||||
, compactSwitch shared
|
||||
, cardSize shared
|
||||
, speechSwitch shared
|
||||
, notificationsSwitch shared
|
||||
]
|
||||
@@ -144,6 +147,22 @@ onJoinLobby auth name model =
|
||||
( { model | settings = updatedSettings }, LocalStorage.store updatedSettings )
|
||||
|
||||
|
||||
{-| Replace a token in our storage because it has been updated.
|
||||
-}
|
||||
onTokenUpdate : Lobby.Auth -> Model -> ( Model, Cmd msg )
|
||||
onTokenUpdate auth model =
|
||||
let
|
||||
settings =
|
||||
model.settings
|
||||
|
||||
updatedSettings =
|
||||
{ settings
|
||||
| tokens = Dict.insert (auth.claims.gc |> GameCode.toString) auth.token settings.tokens
|
||||
}
|
||||
in
|
||||
( { model | settings = updatedSettings }, LocalStorage.store updatedSettings )
|
||||
|
||||
|
||||
{-| Get all the tokens in settings as `Auth`s by game code.
|
||||
-}
|
||||
auths : Settings -> Dict String Lobby.Auth
|
||||
@@ -171,8 +190,8 @@ changeSettings f model =
|
||||
( { model | settings = settings }, LocalStorage.store settings )
|
||||
|
||||
|
||||
compactSwitch : Shared -> Html Global.Msg
|
||||
compactSwitch shared =
|
||||
cardSize : Shared -> Html Global.Msg
|
||||
cardSize shared =
|
||||
let
|
||||
model =
|
||||
shared.settings
|
||||
@@ -181,29 +200,60 @@ compactSwitch shared =
|
||||
model.settings
|
||||
in
|
||||
Form.section shared
|
||||
"compact-cards"
|
||||
"card-size"
|
||||
(Html.div
|
||||
[ HtmlA.class "multipart" ]
|
||||
[ Wl.switch
|
||||
[ HtmlA.checked settings.compactCards
|
||||
, HtmlE.onCheck (ChangeCompactCards >> Global.SettingsMsg)
|
||||
[ Wl.slider
|
||||
[ HtmlA.class "primary"
|
||||
, Slider.step 1
|
||||
, Slider.min 1
|
||||
, Slider.max 3
|
||||
, WlA.label "Card Size"
|
||||
, WlA.outlined
|
||||
, Slider.thumbLabel True
|
||||
, String.toInt
|
||||
>> Maybe.andThen cardSizeFromValue
|
||||
>> Maybe.withDefault Full
|
||||
>> ChangeCardSize
|
||||
>> Global.SettingsMsg
|
||||
|> HtmlE.onInput
|
||||
, model.settings.cardSize |> cardSizeToValue |> String.fromInt |> WlA.value
|
||||
]
|
||||
, Html.label []
|
||||
[ Icon.view Icon.searchMinus
|
||||
, Html.text " "
|
||||
, Strings.CompactCardsSetting |> Lang.html shared
|
||||
[ Icon.viewStyled [ Slider.slot Slider.Before ] Icon.searchMinus
|
||||
, [ model.settings.cardSize |> cardSizeThumb ] |> Html.span [ Slider.slot Slider.ThumbLabel ]
|
||||
, Icon.viewStyled [ Slider.slot Slider.After ] Icon.searchPlus
|
||||
]
|
||||
]
|
||||
-- [ Wl.switch
|
||||
-- [ HtmlA.checked settings.compactCards
|
||||
-- , HtmlE.onCheck (ChangeCompactCards >> Global.SettingsMsg)
|
||||
-- ]
|
||||
-- , Html.label []
|
||||
-- [ Icon.view Icon.searchMinus
|
||||
-- , Html.text " "
|
||||
-- , Strings.CompactCardsSetting |> Lang.html shared
|
||||
-- ]
|
||||
-- ]
|
||||
)
|
||||
[ Message.info Strings.CompactCardsExplanation ]
|
||||
[ Message.info Strings.CardSizeExplanation ]
|
||||
|
||||
|
||||
cardSizeThumb : CardSize -> Html msg
|
||||
cardSizeThumb size =
|
||||
case size of
|
||||
Minimal ->
|
||||
Icon.view Icon.minimalCardSize
|
||||
|
||||
-- TODO: Impl
|
||||
Square ->
|
||||
Icon.view Icon.squareCardSize
|
||||
|
||||
Full ->
|
||||
Icon.view Icon.callCard
|
||||
|
||||
|
||||
speechSwitch : Shared -> Html Global.Msg
|
||||
speechSwitch shared =
|
||||
-- TODO: Impl
|
||||
Form.section shared
|
||||
"speech"
|
||||
(Html.div
|
||||
@@ -219,12 +269,9 @@ speechSwitch shared =
|
||||
[ Message.info Strings.SpeechExplanation ]
|
||||
|
||||
|
||||
|
||||
-- TODO: Impl
|
||||
|
||||
|
||||
notificationsSwitch : Shared -> Html Global.Msg
|
||||
notificationsSwitch shared =
|
||||
-- TODO: Impl
|
||||
Form.section shared
|
||||
"notifications"
|
||||
(Html.div
|
||||
|
||||
@@ -2,12 +2,13 @@ module MassiveDecks.Settings.Messages exposing (Msg(..))
|
||||
|
||||
import Dict exposing (Dict)
|
||||
import MassiveDecks.Pages.Lobby.Model as Lobby
|
||||
import MassiveDecks.Settings.Model exposing (..)
|
||||
import MassiveDecks.Strings.Languages.Model exposing (Language)
|
||||
|
||||
|
||||
type Msg
|
||||
= ChangeLang (Maybe Language)
|
||||
| ChangeCompactCards Bool
|
||||
| ChangeCardSize CardSize
|
||||
| ChangeOpenUserList Bool
|
||||
| ToggleOpen
|
||||
| RemoveInvalid (Dict Lobby.Token Bool)
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
module MassiveDecks.Settings.Model exposing (Model, Settings)
|
||||
module MassiveDecks.Settings.Model exposing
|
||||
( CardSize(..)
|
||||
, Model
|
||||
, Settings
|
||||
, cardSizeFromValue
|
||||
, cardSizeToValue
|
||||
, cardSizes
|
||||
)
|
||||
|
||||
import Dict exposing (Dict)
|
||||
import MassiveDecks.Card.Source.Model as Source exposing (Source)
|
||||
@@ -23,5 +30,45 @@ type alias Settings =
|
||||
, lastUsedName : Maybe String
|
||||
, recentDecks : List Source.External
|
||||
, chosenLanguage : Maybe Language
|
||||
, compactCards : Bool
|
||||
, cardSize : CardSize
|
||||
}
|
||||
|
||||
|
||||
type CardSize
|
||||
= Minimal
|
||||
| Square
|
||||
| Full
|
||||
|
||||
|
||||
cardSizes : List CardSize
|
||||
cardSizes =
|
||||
[ Minimal, Square, Full ]
|
||||
|
||||
|
||||
cardSizeToValue : CardSize -> Int
|
||||
cardSizeToValue size =
|
||||
case size of
|
||||
Minimal ->
|
||||
1
|
||||
|
||||
Square ->
|
||||
2
|
||||
|
||||
Full ->
|
||||
3
|
||||
|
||||
|
||||
cardSizeFromValue : Int -> Maybe CardSize
|
||||
cardSizeFromValue size =
|
||||
case size of
|
||||
1 ->
|
||||
Just Minimal
|
||||
|
||||
2 ->
|
||||
Just Square
|
||||
|
||||
3 ->
|
||||
Just Full
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
|
||||
@@ -68,8 +68,8 @@ type MdString
|
||||
| LanguageSetting -- The label for the "Language" setting.
|
||||
| MissingLanguage -- A question asking if the user doesn't see the language they want.
|
||||
| TranslationBeg -- A request for help translating the game.
|
||||
| CompactCardsSetting -- The label for the "Compact Cards" setting.
|
||||
| CompactCardsExplanation -- An explanation of what compact cards does (makes cards square).
|
||||
| CardSizeSetting -- The label for the "Card Size" setting.
|
||||
| CardSizeExplanation -- An explanation of what the card size does (changes the size of the card).
|
||||
| SpeechSetting -- The label for the speech setting.
|
||||
| SpeechExplanation -- An explanation of what the speech setting does (enables TTS on cards).
|
||||
| NotificationsSetting -- The label for the notifications setting.
|
||||
@@ -133,6 +133,8 @@ type MdString
|
||||
| InvitePlayers -- A short term for inviting players to the game.
|
||||
| SetAway -- A short term for leaving the game temporarily.
|
||||
| LeaveGame -- A short term for the action of leaving the game permanently.
|
||||
| EndGame -- A short term for the action of ending the game early.
|
||||
| EndGameDescription -- A description of the action of ending the game early.
|
||||
| KickUser -- A short term for the action of forcing a user to leave the game permanently.
|
||||
| Promote -- A short term for the action of allowing a user to edit the game configuration.
|
||||
-- Notifications
|
||||
@@ -173,17 +175,20 @@ type MdString
|
||||
| TakeBackPlay -- A description of the action of taking back a previously submitted play.
|
||||
| JudgePlay -- A description of the action of choosing a play to win the round.
|
||||
| LikePlay -- A description of the action of liking a play.
|
||||
| AdvanceRound -- A description of the action of finishing looking at the winner and advancing to the next round.
|
||||
| Playing -- A description of the stage of the round where players are playing responses into the round.
|
||||
| Revealing -- A description of the stage of the round where the czar is revealing the plays.
|
||||
| Judging -- A description of the stage of the round where the czar is picking a winner.
|
||||
| Complete -- A description of the stage of the round where it is finished.
|
||||
-- Instructions
|
||||
| WhatToDo -- A description of the action of asking for help on what to do in the game at this time.
|
||||
| PlayInstruction { numberOfCards : Int } -- Instruction to the player on how to play cards.
|
||||
| SubmitInstruction -- Instruction to the player on how to submit their play.
|
||||
| WaitingForPlaysInstruction -- Instruction to the player that they need to wait for other players to play.
|
||||
| CzarsDontPlayInstruction -- Instruction to the player that as Czar they don't play into the round.
|
||||
| RevealPlaysInstruction -- Instruction to reveal plays for the round.
|
||||
| WaitingForCzarInstruction -- Instruction to wait for the czar to reveal plays and pick a winner.
|
||||
| AdvanceRoundInstruction -- Instruction that the next round is ready and they can advance.
|
||||
-- 404 Unknown
|
||||
| UnknownPageTitle -- A title explaining the page the user tried to go to doesn't exist.
|
||||
| GoBackHome -- The action to go back to the main page of the application.
|
||||
|
||||
@@ -250,11 +250,11 @@ translate mdString =
|
||||
, Text "!"
|
||||
]
|
||||
|
||||
CompactCardsSetting ->
|
||||
CardSizeSetting ->
|
||||
[ Text "Compact Cards" ]
|
||||
|
||||
CompactCardsExplanation ->
|
||||
[ Text "Show cards as square—this is useful on small screens to fit more cards on at once." ]
|
||||
CardSizeExplanation ->
|
||||
[ Text "Adjust how big cards are—this can be useful on small screens to scroll less." ]
|
||||
|
||||
SpeechSetting ->
|
||||
[ Text "Text To Speech" ]
|
||||
@@ -475,6 +475,12 @@ translate mdString =
|
||||
LeaveGame ->
|
||||
[ Text "Leave Game" ]
|
||||
|
||||
EndGame ->
|
||||
[ Text "End Game" ]
|
||||
|
||||
EndGameDescription ->
|
||||
[ Text "End the game early." ]
|
||||
|
||||
KickUser ->
|
||||
[ Text "Kick" ]
|
||||
|
||||
@@ -609,6 +615,9 @@ translate mdString =
|
||||
LikePlay ->
|
||||
[ Text "Add a like to this play." ]
|
||||
|
||||
AdvanceRound ->
|
||||
[ Text "Next round." ]
|
||||
|
||||
Playing ->
|
||||
[ Text "Playing" ]
|
||||
|
||||
@@ -622,6 +631,9 @@ translate mdString =
|
||||
[ Text "Finished" ]
|
||||
|
||||
-- Instructions
|
||||
WhatToDo ->
|
||||
[ Text "What should I be doing?" ]
|
||||
|
||||
PlayInstruction { numberOfCards } ->
|
||||
[ Text "You need to choose "
|
||||
, Text (asWord numberOfCards)
|
||||
@@ -648,7 +660,10 @@ translate mdString =
|
||||
[ Text "Click on the plays to flip them, then pick the one you think is best." ]
|
||||
|
||||
WaitingForCzarInstruction ->
|
||||
[ Text "You ware waiting for the ", Ref Czar, Text " to reveal the plays and pick a winner for the round." ]
|
||||
[ Text "You can like plays while you wait for the ", Ref Czar, Text " to reveal the plays and pick a winner for the round." ]
|
||||
|
||||
AdvanceRoundInstruction ->
|
||||
[ Text "The next round has started, you can advance." ]
|
||||
|
||||
-- 404 Unknown
|
||||
UnknownPageTitle ->
|
||||
|
||||
@@ -154,7 +154,7 @@ enhanceHtml context mdString unenhanced =
|
||||
prefixed unenhanced Icon.parachuteBox
|
||||
|
||||
HouseRuleReboot ->
|
||||
prefixed unenhanced Icon.redo
|
||||
prefixed unenhanced Icon.random
|
||||
|
||||
HouseRuleRandoCardrissian ->
|
||||
prefixed unenhanced Icon.robot
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module MassiveDecks.Util exposing
|
||||
( lift
|
||||
( batchUpdate
|
||||
, lift
|
||||
, messageLift
|
||||
, modelLift
|
||||
)
|
||||
@@ -27,3 +28,27 @@ messageLift liftMsg ( model, subCmd ) =
|
||||
modelLift : (subModel -> model) -> ( subModel, Cmd msg ) -> ( model, Cmd msg )
|
||||
modelLift liftModel ( subModel, cmd ) =
|
||||
( liftModel subModel, cmd )
|
||||
|
||||
|
||||
{-| Perform the given update task for each of the messages in a row.
|
||||
-}
|
||||
batchUpdate : List msg -> model -> (msg -> model -> ( model, Cmd cmdMsg )) -> ( model, Cmd cmdMsg )
|
||||
batchUpdate messages model update =
|
||||
let
|
||||
( newModel, cmdList ) =
|
||||
messages |> List.foldl (batchUpdateStep update) ( model, [] )
|
||||
in
|
||||
( newModel, cmdList |> List.reverse |> Cmd.batch )
|
||||
|
||||
|
||||
|
||||
{- Private -}
|
||||
|
||||
|
||||
batchUpdateStep : (msg -> model -> ( model, Cmd cmdMsg )) -> msg -> ( model, List (Cmd cmdMsg) ) -> ( model, List (Cmd cmdMsg) )
|
||||
batchUpdateStep update msg ( model, cmdList ) =
|
||||
let
|
||||
( newModel, newCmd ) =
|
||||
update msg model
|
||||
in
|
||||
( newModel, newCmd :: cmdList )
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
module Reread exposing (icon, mdIcon)
|
||||
|
||||
import FontAwesome.Icon as Icon exposing (Icon)
|
||||
|
||||
|
||||
icon : Icon
|
||||
icon =
|
||||
Icon "fab" "reread" 512 512 "M258 16c-62 0-124 24-171 71-95 94-94 246 0 339 95 93 250 93 345 0l12-12-15-14-12 12-10-10c-82 80-213 80-295 0-82-81-82-210-1-291 81-80 212-81 294-3l-38 35 129 25-1-3-26-117-39 36c-48-46-110-68-172-68zm-79 159c-46 1-70 10-70 10v133s24-9 70-9c50 0 70 20 70 20V196s-20-21-70-21zm160 0c-50 0-70 21-70 21v133s20-20 70-20c46 0 70 9 70 9V185s-24-9-70-10zM179 323c-46 1-70 10-70 10v16s24-9 70-9c50 0 81 31 81 31s30-31 80-31c46 0 70 9 70 9v-16s-24-9-70-10c-50 0-80 32-80 32s-31-32-81-32z"
|
||||
|
||||
|
||||
mdIcon : Icon
|
||||
mdIcon =
|
||||
Icon "fab" "massivedecks" 512 512 "M273 20c-11 0-21 9-23 21l-9 88h-8L39 163c-12 2-21 15-19 27l50 283c2 12 15 21 27 19l194-34c12-3 21-15 18-27l-13-73 140 14c13 2 25-8 26-20l30-286c1-13-8-24-21-25L276 20h-3zm0 16h1l196 21c4 0 6 3 6 7l-30 286c0 4-4 7-8 6l-144-15-35-193-3-9 10-97c1-3 4-6 7-6zm47 106l-10 99 39 4c15 2 25 0 32-8 9-8 15-21 16-37 2-15-1-29-8-39-6-9-15-13-30-15zm19 20l18 1c16 2 22 14 20 35-3 22-11 32-27 31l-18-2zm-135 91l17 98-20 4-13-77-4 80-20 3-32-73 14 76-20 4-18-98 31-6 31 75 4-81z"
|
||||
@@ -7,6 +7,7 @@ module Weightless exposing
|
||||
, popover
|
||||
, popoverCard
|
||||
, select
|
||||
, slider
|
||||
, switch
|
||||
, tab
|
||||
, tabGroup
|
||||
@@ -39,29 +40,9 @@ listItem =
|
||||
Html.node "wl-list-item"
|
||||
|
||||
|
||||
tabGroup : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
tabGroup =
|
||||
Html.node "wl-tab-group"
|
||||
|
||||
|
||||
tab : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
tab =
|
||||
Html.node "wl-tab"
|
||||
|
||||
|
||||
switch : List (Html.Attribute msg) -> Html msg
|
||||
switch attrs =
|
||||
Html.node "wl-switch" attrs []
|
||||
|
||||
|
||||
textField : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
textField =
|
||||
Html.node "wl-textfield"
|
||||
|
||||
|
||||
textArea : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
textArea =
|
||||
Html.node "wl-textarea"
|
||||
navigationBar : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
navigationBar =
|
||||
Html.node "wl-nav"
|
||||
|
||||
|
||||
popover : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
@@ -74,16 +55,41 @@ popoverCard =
|
||||
Html.node "wl-popover-card"
|
||||
|
||||
|
||||
navigationBar : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
navigationBar =
|
||||
Html.node "wl-nav"
|
||||
|
||||
|
||||
select : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
select =
|
||||
Html.node "wl-select"
|
||||
|
||||
|
||||
slider : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
slider =
|
||||
Html.node "wl-slider"
|
||||
|
||||
|
||||
switch : List (Html.Attribute msg) -> Html msg
|
||||
switch attrs =
|
||||
Html.node "wl-switch" attrs []
|
||||
|
||||
|
||||
tab : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
tab =
|
||||
Html.node "wl-tab"
|
||||
|
||||
|
||||
tabGroup : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
tabGroup =
|
||||
Html.node "wl-tab-group"
|
||||
|
||||
|
||||
textArea : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
textArea =
|
||||
Html.node "wl-textarea"
|
||||
|
||||
|
||||
textField : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
textField =
|
||||
Html.node "wl-textfield"
|
||||
|
||||
|
||||
tooltip : List (Html.Attribute msg) -> List (Html msg) -> Html msg
|
||||
tooltip =
|
||||
Html.node "wl-tooltip"
|
||||
|
||||
@@ -37,6 +37,7 @@ module Weightless.Attributes exposing
|
||||
, outlined
|
||||
, readonly
|
||||
, selected
|
||||
, step
|
||||
, textFieldSlot
|
||||
, transformOrigin
|
||||
, type_
|
||||
@@ -49,6 +50,11 @@ import Html.Attributes as HtmlA
|
||||
import Json.Encode as Json
|
||||
|
||||
|
||||
step : Int -> Html.Attribute msg
|
||||
step =
|
||||
numberAttr "step"
|
||||
|
||||
|
||||
min : Int -> Html.Attribute msg
|
||||
min =
|
||||
numberAttr "min"
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
module Weightless.Internal exposing
|
||||
( boolProp
|
||||
, numberAttr
|
||||
, numberProp
|
||||
, presentAttribute
|
||||
, stringArrayProperty
|
||||
, stringAttr
|
||||
)
|
||||
|
||||
import Html
|
||||
import Html.Attributes as HtmlA
|
||||
import Json.Encode as Json
|
||||
|
||||
|
||||
presentAttribute : String -> Html.Attribute msg
|
||||
presentAttribute attribute =
|
||||
HtmlA.attribute attribute attribute
|
||||
|
||||
|
||||
stringArrayProperty : String -> List String -> Html.Attribute msg
|
||||
stringArrayProperty property values =
|
||||
HtmlA.property property (values |> Json.list Json.string)
|
||||
|
||||
|
||||
stringAttr : String -> String -> Html.Attribute msg
|
||||
stringAttr attribute stringValue =
|
||||
HtmlA.attribute attribute stringValue
|
||||
|
||||
|
||||
numberAttr : String -> Int -> Html.Attribute msg
|
||||
numberAttr attribute intValue =
|
||||
intValue |> String.fromInt |> HtmlA.attribute attribute
|
||||
|
||||
|
||||
numberProp : String -> Int -> Html.Attribute msg
|
||||
numberProp property intValue =
|
||||
intValue |> Json.int |> HtmlA.property property
|
||||
|
||||
|
||||
boolProp : String -> Bool -> Html.Attribute msg
|
||||
boolProp property boolValue =
|
||||
boolValue |> Json.bool |> HtmlA.property property
|
||||
@@ -0,0 +1,54 @@
|
||||
module Weightless.Slider exposing
|
||||
( Slot(..)
|
||||
, max
|
||||
, min
|
||||
, slot
|
||||
, step
|
||||
, thumbLabel
|
||||
)
|
||||
|
||||
import Html
|
||||
import Weightless.Internal as Internal
|
||||
|
||||
|
||||
type Slot
|
||||
= Before
|
||||
| After
|
||||
| ThumbLabel
|
||||
|
||||
|
||||
slot : Slot -> Html.Attribute msg
|
||||
slot s =
|
||||
let
|
||||
textSlot =
|
||||
case s of
|
||||
Before ->
|
||||
"before"
|
||||
|
||||
After ->
|
||||
"after"
|
||||
|
||||
ThumbLabel ->
|
||||
"thumb-label"
|
||||
in
|
||||
Internal.stringAttr "slot" textSlot
|
||||
|
||||
|
||||
step : Int -> Html.Attribute msg
|
||||
step =
|
||||
Internal.numberProp "step"
|
||||
|
||||
|
||||
min : Int -> Html.Attribute msg
|
||||
min =
|
||||
Internal.numberProp "min"
|
||||
|
||||
|
||||
max : Int -> Html.Attribute msg
|
||||
max =
|
||||
Internal.numberProp "max"
|
||||
|
||||
|
||||
thumbLabel : Bool -> Html.Attribute msg
|
||||
thumbLabel =
|
||||
Internal.boolProp "thumbLabel"
|
||||
@@ -0,0 +1,98 @@
|
||||
@import "./variables";
|
||||
|
||||
.minimal-card-size #game {
|
||||
--card-aspect-ratio: 0;
|
||||
|
||||
ul.cards {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
ul.card-set {
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
|
||||
li {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
:not(.background-plays) .game-card {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
width: auto;
|
||||
|
||||
.content {
|
||||
p {
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aspect {
|
||||
position: static;
|
||||
height: auto;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
|
||||
transition: none;
|
||||
|
||||
& > * {
|
||||
position: static;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.side.back {
|
||||
display: none;
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "?";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.face-down {
|
||||
.side {
|
||||
&.back {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.front {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.round {
|
||||
justify-content: stretch;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.liked {
|
||||
.side::after {
|
||||
right: 1em;
|
||||
top: 50%;
|
||||
margin-top: -1.5em;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.square-card-size #game {
|
||||
--card-aspect-ratio: #{$card-compact-ratio};
|
||||
}
|
||||
@@ -2,12 +2,9 @@
|
||||
@import "./colors";
|
||||
@import "./fonts";
|
||||
@import "./card/sources";
|
||||
@import "./card/size";
|
||||
|
||||
.compact-cards .card-area {
|
||||
--card-aspect-ratio: #{$card-compact-ratio};
|
||||
}
|
||||
|
||||
.card-area {
|
||||
#game {
|
||||
--card-aspect-ratio: #{$card-ratio};
|
||||
@include fluid-type(20rem, 64rem, 0.5rem, 0.8rem);
|
||||
}
|
||||
@@ -59,12 +56,14 @@
|
||||
height: 1em;
|
||||
flex-grow: 1;
|
||||
flex-basis: 2em;
|
||||
max-width: 14em;
|
||||
border-bottom: 0.1em solid var(--fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a fixed size from an aspect ratio.
|
||||
.aspect {
|
||||
transition: transform 0.75s;
|
||||
transform-style: preserve-3d;
|
||||
@@ -73,7 +72,7 @@
|
||||
width: 100%;
|
||||
@include pad-to-aspect-ratio(var(--card-aspect-ratio));
|
||||
|
||||
& > * {
|
||||
& .side {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@@ -129,6 +128,7 @@
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
// For custom cards.
|
||||
textarea {
|
||||
display: block;
|
||||
vertical-align: top;
|
||||
@@ -179,16 +179,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.error .side {
|
||||
border-color: $error;
|
||||
}
|
||||
}
|
||||
|
||||
.picked {
|
||||
position: relative;
|
||||
|
||||
.side {
|
||||
border-color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
+88
-220
@@ -1,81 +1,23 @@
|
||||
@import "card/variables";
|
||||
@import "colors";
|
||||
@import "./card/variables";
|
||||
@import "./colors";
|
||||
@import "~weightless/style/base/elevation";
|
||||
@import "./game/judging";
|
||||
@import "./game/playing";
|
||||
@import "./game/plays";
|
||||
@import "./pages/lobby/variables";
|
||||
|
||||
// The main game area.
|
||||
#game {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
.card-area {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.context-help {
|
||||
position: fixed;
|
||||
top: 4em;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
|
||||
background-color: $secondary-background;
|
||||
padding: 0.5em;
|
||||
border-bottom-left-radius: 1em;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
|
||||
transition: transform 200ms ease-out;
|
||||
transform: translate(calc(100% - 2em), 0);
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
transform: translate(0, 0);
|
||||
transition: transform 200ms ease-in;
|
||||
}
|
||||
|
||||
& > svg {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-top {
|
||||
pointer-events: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
wl-button {
|
||||
pointer-events: all;
|
||||
position: sticky;
|
||||
bottom: 0.5em;
|
||||
margin: 0.5em;
|
||||
z-index: 1;
|
||||
|
||||
opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This pushes the scroll-top button down below the page content.
|
||||
.scroll-top-spacer {
|
||||
height: 6em;
|
||||
}
|
||||
|
||||
// A button that allows the user to perform the main action in the game for them at this moment.
|
||||
.action {
|
||||
position: fixed;
|
||||
// Hack because the debugger covers it up.
|
||||
// TODO: Remove Hack (here because the debugger covers it up).
|
||||
bottom: 5rem;
|
||||
//bottom: 1em;
|
||||
right: 1rem;
|
||||
@@ -84,179 +26,105 @@
|
||||
|
||||
--button-fab-size: 4rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
// A style for actions that the game is waiting on - high contrast to grab attention.
|
||||
.important {
|
||||
--button-bg: #{$secondary};
|
||||
--button-color: #{$on-secondary};
|
||||
--button-bg-hover: #{$secondary-light};
|
||||
--button-color-hover: #{$on-secondary-light};
|
||||
--button-bg-active: #{$secondary-dark};
|
||||
--button-color-acitve: #{$on-secondary-dark};
|
||||
// A style for actions that the game is waiting on - high contrast to grab attention.
|
||||
&.important {
|
||||
--button-bg: #{$secondary};
|
||||
--button-color: #{$on-secondary};
|
||||
--button-bg-hover: #{$secondary-light};
|
||||
--button-color-hover: #{$on-secondary-light};
|
||||
--button-bg-active: #{$secondary-dark};
|
||||
--button-color-acitve: #{$on-secondary-dark};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.play-area {
|
||||
overflow: hidden;
|
||||
// Contextual help for the player telling them what they need to do at this point in the game.
|
||||
#context-help {
|
||||
font-size: 1.2rem;
|
||||
position: fixed;
|
||||
top: $top-bar-height;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
--card-padding: 0.5em;
|
||||
|
||||
#context-help-button {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
wl-popover-card {
|
||||
min-width: 10em;
|
||||
}
|
||||
}
|
||||
|
||||
// The button to scroll to the top of the game area.
|
||||
.scroll-top {
|
||||
pointer-events: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
wl-button {
|
||||
pointer-events: all;
|
||||
position: sticky;
|
||||
bottom: 0.5em;
|
||||
margin: 0.5em;
|
||||
z-index: 1;
|
||||
|
||||
opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This pushes the scroll-top button down below the page content.
|
||||
.scroll-top-spacer {
|
||||
height: 6em;
|
||||
}
|
||||
|
||||
// Where the call for the round is displayed.
|
||||
.round {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
flex-basis: $card-width;
|
||||
align-items: center;
|
||||
min-width: $card-width;
|
||||
padding: 2em 0;
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
.cards-in-play {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
// A play or card that has been picked by the player as the target of some action.
|
||||
.game-card,
|
||||
ol.card-set {
|
||||
&.picked {
|
||||
.side {
|
||||
border-color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hand {
|
||||
margin-top: 0.5em;
|
||||
|
||||
// Display some number of cards or card sets together.
|
||||
ul.cards {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
||||
position: relative;
|
||||
|
||||
&.not-playing {
|
||||
pointer-events: none;
|
||||
|
||||
.game-card .aspect::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 0.75em;
|
||||
background-color: #000000;
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.background-plays {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: -10;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-evenly;
|
||||
|
||||
.play {
|
||||
position: relative;
|
||||
transform: translateY(-100%);
|
||||
transition: transform 500ms ease-in;
|
||||
width: $card-width + $card-margin * 2;
|
||||
@include pad-to-aspect-ratio(var(--card-aspect-ratio));
|
||||
|
||||
.game-card {
|
||||
transform: rotate(0);
|
||||
transition: transform 500ms ease-in;
|
||||
transform-origin: center;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&.played {
|
||||
transform: translateY(0);
|
||||
transition: transform 500ms ease-out;
|
||||
|
||||
.game-card {
|
||||
transform: rotate(var(--rotation));
|
||||
transition: transform 500ms ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.plays {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
// Multiple cards that are grouped together.
|
||||
ol.card-set {
|
||||
margin: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
||||
position: relative;
|
||||
|
||||
.play-with-byline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.byline {
|
||||
font-size: 2em;
|
||||
text-align: center;
|
||||
|
||||
svg {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.play {
|
||||
display: flex;
|
||||
margin: 1em;
|
||||
|
||||
.overlap {
|
||||
flex-shrink: 1;
|
||||
flex-grow: 0;
|
||||
flex-basis: $card-width;
|
||||
overflow: visible;
|
||||
z-index: 0;
|
||||
|
||||
&:last-of-type {
|
||||
width: $card-width;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.game-card {
|
||||
margin: 0 $card-margin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.liked {
|
||||
.side::after {
|
||||
position: absolute;
|
||||
bottom: 1em;
|
||||
right: 1em;
|
||||
width: 8em;
|
||||
height: 8em;
|
||||
transform: rotate(-0.125turn);
|
||||
|
||||
display: block;
|
||||
content: "";
|
||||
opacity: 0.3;
|
||||
//noinspection CssInvalidFunction
|
||||
background: inline-svg(
|
||||
"./assets/images/certificate-thumbs-up.svg",
|
||||
(
|
||||
path: (
|
||||
fill: $primary
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
@import "../colors";
|
||||
|
||||
.liked {
|
||||
.side::after {
|
||||
position: absolute;
|
||||
bottom: 1em;
|
||||
right: 1em;
|
||||
width: 8em;
|
||||
height: 8em;
|
||||
transform: rotate(-0.125turn);
|
||||
|
||||
display: block;
|
||||
content: "";
|
||||
opacity: 0.3;
|
||||
//noinspection CssInvalidFunction
|
||||
background: inline-svg(
|
||||
"./assets/images/certificate-thumbs-up.svg",
|
||||
(
|
||||
path: (
|
||||
fill: $primary
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
@import "../card/variables";
|
||||
|
||||
// A hand of cards.
|
||||
.hand {
|
||||
margin-top: 0.5em;
|
||||
|
||||
position: relative;
|
||||
|
||||
&.not-playing {
|
||||
pointer-events: none;
|
||||
|
||||
.game-card .aspect::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 0.75em;
|
||||
background-color: #000000;
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unknown plays for the round animated in at the top of the screen during the playing stage.
|
||||
.background-plays {
|
||||
--card-aspect-ratio: #{$card-ratio};
|
||||
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: -10;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-evenly;
|
||||
|
||||
.play {
|
||||
position: relative;
|
||||
transform: translateY(-100%);
|
||||
transition: transform 500ms ease-in;
|
||||
width: $card-width + $card-margin * 2;
|
||||
@include pad-to-aspect-ratio(var(--card-aspect-ratio));
|
||||
|
||||
.game-card {
|
||||
transform: rotate(0);
|
||||
transition: transform 500ms ease-in;
|
||||
transform-origin: center;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&.played {
|
||||
transform: translateY(0);
|
||||
transition: transform 500ms ease-out;
|
||||
|
||||
.game-card {
|
||||
transform: rotate(var(--rotation));
|
||||
transition: transform 500ms ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// A play with the user's name.
|
||||
.play-with-byline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// The user's name.
|
||||
.byline {
|
||||
font-size: 2em;
|
||||
text-align: center;
|
||||
|
||||
svg {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
@@ -3,42 +3,27 @@
|
||||
@import "../game";
|
||||
@import "./lobby/configure";
|
||||
@import "./lobby/invite";
|
||||
@import "./lobby/variables";
|
||||
@import "~weightless/style/base/elevation";
|
||||
|
||||
$users-width: 15em;
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
.lobby {
|
||||
box-sizing: border-box;
|
||||
height: 100vh;
|
||||
padding-top: 4em;
|
||||
overflow: hidden;
|
||||
|
||||
.content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
min-width: fit-content;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
#lobby {
|
||||
}
|
||||
|
||||
#top-bar {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
z-index: 10;
|
||||
|
||||
height: 4em;
|
||||
height: $top-bar-height;
|
||||
padding: 0 1em;
|
||||
|
||||
display: flex;
|
||||
@@ -55,57 +40,30 @@ $users-width: 15em;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.title-call {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
|
||||
margin: 0 1em;
|
||||
|
||||
white-space: pre;
|
||||
font-size: 1em;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-family: "Helvetica Neue", "Nimbus Sans L", sans-serif;
|
||||
font-weight: 700;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.slot {
|
||||
display: inline-block;
|
||||
flex-shrink: 0;
|
||||
flex-basis: 3em;
|
||||
border-bottom: 0.1em solid $call-color;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "“";
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "”";
|
||||
}
|
||||
}
|
||||
#lobby-content {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: $top-bar-height;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
box-sizing: border-box;
|
||||
min-width: fit-content;
|
||||
}
|
||||
|
||||
#scroll-frame {
|
||||
flex-grow: 100;
|
||||
flex-shrink: 1;
|
||||
flex-basis: $card-width;
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
min-width: $card-width;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: $users-width;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
transition: left 0.3s;
|
||||
}
|
||||
|
||||
.outlined-solid-icon {
|
||||
path {
|
||||
fill: none;
|
||||
stroke: black;
|
||||
stroke-width: 32px;
|
||||
}
|
||||
.collapsed-users #scroll-frame {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.loading {
|
||||
@@ -119,23 +77,9 @@ $users-width: 15em;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.collapsed-users .users {
|
||||
flex-grow: 0;
|
||||
flex-basis: 0;
|
||||
}
|
||||
|
||||
.context-help {
|
||||
left: $users-width;
|
||||
}
|
||||
|
||||
.collapsed-users .context-help {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.users {
|
||||
#users {
|
||||
font-size: 1rem;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
overflow: auto;
|
||||
|
||||
z-index: 2;
|
||||
|
||||
@@ -143,16 +87,15 @@ $users-width: 15em;
|
||||
|
||||
padding: 0;
|
||||
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
|
||||
min-height: 100%;
|
||||
|
||||
flex-basis: $users-width;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: $users-width;
|
||||
|
||||
transition: flex-basis 0.3s, flex-grow 0.3s, padding-left 0.3s,
|
||||
padding-right 0.3s;
|
||||
transition: width 0.3s;
|
||||
|
||||
--list-item-padding: 0.5em;
|
||||
|
||||
@@ -180,6 +123,20 @@ $users-width: 15em;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $users-width * 2) {
|
||||
#scroll-frame {
|
||||
left: 100vw;
|
||||
}
|
||||
|
||||
#users {
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
.collapsed-users #users {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.cast-button {
|
||||
&.connecting {
|
||||
animation: fadeIn 1s infinite alternate;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
.configure {
|
||||
padding: 1em;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
|
||||
wl-card {
|
||||
max-width: 30em;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
$top-bar-height: 4rem;
|
||||
$users-width: 15rem;
|
||||
@@ -7,6 +7,7 @@ import "weightless/nav";
|
||||
import "weightless/popover";
|
||||
import "weightless/popover-card";
|
||||
import "weightless/select";
|
||||
import "weightless/slider";
|
||||
import "weightless/switch";
|
||||
import "weightless/tab";
|
||||
import "weightless/tab-group";
|
||||
|
||||
Generated
+54
-36
@@ -262,12 +262,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.10.2.tgz",
|
||||
"integrity": "sha512-7449RhjE1oLFIy5E/5rT4wG5+KsfPzakJuhvpzXJ3C46lq7xywY0/Rjo9ZBcwrfbk0nRZ5xmUHkk7DZ67tSBKw==",
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.11.0.tgz",
|
||||
"integrity": "sha512-mXv9ccCou89C8/4avKHuPB2WkSZyY/XcTQUXd5LFZAcLw1I3mWYVjUu6eS9Ja0QkP/ClolbcW9tb3Ov/pMdcqw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "1.10.2",
|
||||
"@typescript-eslint/experimental-utils": "1.11.0",
|
||||
"eslint-utils": "^1.3.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"regexpp": "^2.0.1",
|
||||
@@ -275,31 +275,31 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.10.2.tgz",
|
||||
"integrity": "sha512-Hf5lYcrnTH5Oc67SRrQUA7KuHErMvCf5RlZsyxXPIT6AXa8fKTyfFO6vaEnUmlz48RpbxO4f0fY3QtWkuHZNjg==",
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.11.0.tgz",
|
||||
"integrity": "sha512-7LbfaqF6B8oa8cp/315zxKk8FFzosRzzhF8Kn/ZRsRsnpm7Qcu25cR/9RnAQo5utZ2KIWVgaALr+ZmcbG47ruw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "1.10.2",
|
||||
"@typescript-eslint/typescript-estree": "1.11.0",
|
||||
"eslint-scope": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.10.2.tgz",
|
||||
"integrity": "sha512-xWDWPfZfV0ENU17ermIUVEVSseBBJxKfqBcRCMZ8nAjJbfA5R7NWMZmFFHYnars5MjK4fPjhu4gwQv526oZIPQ==",
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.11.0.tgz",
|
||||
"integrity": "sha512-5xBExyXaxVyczrZvbRKEXvaTUFFq7gIM9BynXukXZE0zF3IQP/FxF4mPmmh3gJ9egafZFqByCpPTFm3dk4SY7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/eslint-visitor-keys": "^1.0.0",
|
||||
"@typescript-eslint/experimental-utils": "1.10.2",
|
||||
"@typescript-eslint/typescript-estree": "1.10.2",
|
||||
"@typescript-eslint/experimental-utils": "1.11.0",
|
||||
"@typescript-eslint/typescript-estree": "1.11.0",
|
||||
"eslint-visitor-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.10.2.tgz",
|
||||
"integrity": "sha512-Kutjz0i69qraOsWeI8ETqYJ07tRLvD9URmdrMoF10bG8y8ucLmPtSxROvVejWvlJUGl2et/plnMiKRDW+rhEhw==",
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.11.0.tgz",
|
||||
"integrity": "sha512-fquUHF5tAx1sM2OeRCC7wVxFd1iMELWMGCzOSmJ3pLzArj9+kRixdlC4d5MncuzXpjEqc6045p3KwM0o/3FuUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash.unescape": "4.0.1",
|
||||
@@ -871,6 +871,12 @@
|
||||
"text-hex": "1.0.x"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"component-emitter": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||
@@ -1151,13 +1157,13 @@
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"eslint": {
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz",
|
||||
"integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz",
|
||||
"integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"ajv": "^6.9.1",
|
||||
"ajv": "^6.10.0",
|
||||
"chalk": "^2.1.0",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"debug": "^4.0.1",
|
||||
@@ -1165,18 +1171,19 @@
|
||||
"eslint-scope": "^4.0.3",
|
||||
"eslint-utils": "^1.3.1",
|
||||
"eslint-visitor-keys": "^1.0.0",
|
||||
"espree": "^5.0.1",
|
||||
"espree": "^6.0.0",
|
||||
"esquery": "^1.0.1",
|
||||
"esutils": "^2.0.2",
|
||||
"file-entry-cache": "^5.0.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"glob": "^7.1.2",
|
||||
"glob-parent": "^3.1.0",
|
||||
"globals": "^11.7.0",
|
||||
"ignore": "^4.0.6",
|
||||
"import-fresh": "^3.0.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"inquirer": "^6.2.2",
|
||||
"js-yaml": "^3.13.0",
|
||||
"is-glob": "^4.0.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.3.0",
|
||||
"lodash": "^4.17.11",
|
||||
@@ -1184,7 +1191,6 @@
|
||||
"mkdirp": "^0.5.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.8.2",
|
||||
"path-is-inside": "^1.0.2",
|
||||
"progress": "^2.0.0",
|
||||
"regexpp": "^2.0.1",
|
||||
"semver": "^5.5.1",
|
||||
@@ -1225,9 +1231,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-config-prettier": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-5.0.0.tgz",
|
||||
"integrity": "sha512-c17Aqiz5e8LEqoc/QPmYnaxQFAHTx2KlCZBPxXXjEMmNchOLnV/7j0HoPZuC+rL/tDC9bazUYOKJW9bOhftI/w==",
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz",
|
||||
"integrity": "sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"get-stdin": "^6.0.0"
|
||||
@@ -1265,9 +1271,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"espree": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz",
|
||||
"integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==",
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz",
|
||||
"integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^6.0.7",
|
||||
@@ -1640,9 +1646,9 @@
|
||||
}
|
||||
},
|
||||
"flatted": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz",
|
||||
"integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
|
||||
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
|
||||
"dev": true
|
||||
},
|
||||
"follow-redirects": {
|
||||
@@ -4404,10 +4410,22 @@
|
||||
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
|
||||
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
|
||||
},
|
||||
"ts-json-schema-generator": {
|
||||
"version": "0.50.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-0.50.2.tgz",
|
||||
"integrity": "sha512-S6n8kHpU2y7IJvr07rA2Xn9wbKRWTs31jvgpFQnkWn4n7jWXOj/yGEzp1UN/qQOBB0r3qSZjsOMr2KzuaSWTGA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "~2.20.0",
|
||||
"glob": "~7.1.4",
|
||||
"json-stable-stringify": "^1.0.1",
|
||||
"typescript": "~3.5.2"
|
||||
}
|
||||
},
|
||||
"ts-postgres": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-postgres/-/ts-postgres-1.0.2.tgz",
|
||||
"integrity": "sha512-WdCth7Q00KrcL2FwxiQq5FM2aUFa2fXqrcOssd537zb8RPa1omhtIZ6Jpi2oL2GjqXEADqar3YPQ4OUbIzjESA==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-postgres/-/ts-postgres-1.1.0.tgz",
|
||||
"integrity": "sha512-POEX+ovAPWyvGqXwBV/xFBJ0Km7sOyfCHjxDMkFIEN3XyzLmEEwPeJM+84SH9kkcDY4Use3senRa7+kkAuDaNQ==",
|
||||
"requires": {
|
||||
"ts-typed-events": "^1.1.1"
|
||||
}
|
||||
|
||||
+6
-6
@@ -17,7 +17,7 @@
|
||||
"start": "node dist/index.js",
|
||||
"dev": "nodemon .",
|
||||
"debug": "nodemon --inspect .",
|
||||
"generate-json-validators": "npx typescript-json-validator src/ts/action/validation.ts --collection --noExtraProps--format=full --aliasRefs --ignoreErrors && sed -i '1s;^;/* eslint-disable */\\n;' src/ts/action/validation.validator.ts",
|
||||
"generate-json-validators": "npx typescript-json-validator src/ts/action/validation.ts --collection --noExtraProps --format=full --aliasRefs --ignoreErrors && sed -i -e 's/allErrors: true/allErrors: false/g' -e 's/ChangeBase<\"\\(.*\\)\",\\(.*\\)>/ChangeBase\\1/g' -e 's/\\/\\* tslint:disable \\*\\//\\/\\* eslint-disable \\*\\//g' src/ts/action/validation.validator.ts",
|
||||
"generate-secret": "npm run prestart && node dist/secret.js"
|
||||
},
|
||||
"files": [
|
||||
@@ -40,7 +40,7 @@
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"moment": "^2.24.0",
|
||||
"source-map-support": "^0.5.12",
|
||||
"ts-postgres": "^1.0.2",
|
||||
"ts-postgres": "^1.1.0",
|
||||
"uuid": "^3.3.2",
|
||||
"winston": "^3.2.1",
|
||||
"wu": "^2.1.0"
|
||||
@@ -57,10 +57,10 @@
|
||||
"@types/source-map-support": "^0.5.0",
|
||||
"@types/uuid": "^3.4.4",
|
||||
"@types/wu": "^2.1.39",
|
||||
"@typescript-eslint/eslint-plugin": "^1.10.2",
|
||||
"@typescript-eslint/parser": "^1.10.2",
|
||||
"eslint": "^5.12.1",
|
||||
"eslint-config-prettier": "^5.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^1.11.0",
|
||||
"@typescript-eslint/parser": "^1.11.0",
|
||||
"eslint": "^6.0.1",
|
||||
"eslint-config-prettier": "^6.0.0",
|
||||
"eslint-plugin-prettier": "^3.1.0",
|
||||
"nodemon": "^1.19.1",
|
||||
"prettier": "1.18.2",
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/* eslint-disable */
|
||||
/* tslint:disable */
|
||||
// generated by typescript-json-validator
|
||||
import Ajv = require("ajv");
|
||||
import { RegisterUser, CreateLobby, Action, CheckAlive } from "./validation";
|
||||
export const ajv = new Ajv({
|
||||
allErrors: false,
|
||||
coerceTypes: false,
|
||||
format: "fast",
|
||||
format: "full",
|
||||
nullable: true,
|
||||
unicode: true,
|
||||
uniqueItems: true,
|
||||
@@ -63,6 +62,7 @@ export const Schema = {
|
||||
]
|
||||
},
|
||||
Authenticate: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "Authenticate with the game.",
|
||||
properties: {
|
||||
@@ -77,6 +77,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
Cardcast: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "A source for Cardcast.",
|
||||
properties: {
|
||||
@@ -94,13 +95,13 @@ export const Schema = {
|
||||
Change: {
|
||||
anyOf: [
|
||||
{
|
||||
$ref: '#/definitions/ChangeBase<"PackingHeat",PackingHeat>'
|
||||
$ref: "#/definitions/ChangeBasePackingHeat"
|
||||
},
|
||||
{
|
||||
$ref: '#/definitions/ChangeBase<"Rando",Rando>'
|
||||
$ref: "#/definitions/ChangeBaseRando"
|
||||
},
|
||||
{
|
||||
$ref: '#/definitions/ChangeBase<"Reboot",Reboot>'
|
||||
$ref: "#/definitions/ChangeBaseReboot"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -125,7 +126,8 @@ export const Schema = {
|
||||
enum: ["Reboot"],
|
||||
type: "string"
|
||||
},
|
||||
'ChangeBase<"PackingHeat",PackingHeat>': {
|
||||
ChangeBasePackingHeat: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
properties: {
|
||||
houseRule: {
|
||||
@@ -138,7 +140,8 @@ export const Schema = {
|
||||
required: ["houseRule"],
|
||||
type: "object"
|
||||
},
|
||||
'ChangeBase<"Rando",Rando>': {
|
||||
ChangeBaseRando: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
properties: {
|
||||
houseRule: {
|
||||
@@ -151,7 +154,8 @@ export const Schema = {
|
||||
required: ["houseRule"],
|
||||
type: "object"
|
||||
},
|
||||
'ChangeBase<"Reboot",Reboot>': {
|
||||
ChangeBaseReboot: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
properties: {
|
||||
houseRule: {
|
||||
@@ -165,6 +169,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
ChangeDecks: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "Make a change to the configuration of decks for the lobby.",
|
||||
properties: {
|
||||
@@ -187,6 +192,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
ChangeHouseRule: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "Set the hand size for the lobby.",
|
||||
properties: {
|
||||
@@ -206,6 +212,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
CheckAlive: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "Previously obtained tokens to check the validity of.",
|
||||
properties: {
|
||||
@@ -220,6 +227,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
CreateLobby: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "The details needed to create a new lobby.",
|
||||
properties: {
|
||||
@@ -246,6 +254,7 @@ export const Schema = {
|
||||
type: "string"
|
||||
},
|
||||
Judge: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "A user declares the winning play for a round.",
|
||||
properties: {
|
||||
@@ -306,6 +315,7 @@ export const Schema = {
|
||||
type: "string"
|
||||
},
|
||||
PackingHeat: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: 'Configuration for the "Packing Heat" house rule.',
|
||||
type: "object"
|
||||
@@ -319,6 +329,7 @@ export const Schema = {
|
||||
type: "string"
|
||||
},
|
||||
Rando: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
properties: {
|
||||
number: {
|
||||
@@ -332,6 +343,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
Reboot: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description:
|
||||
'Configuration for the "Reboot the Universe" house rule.\nThis rule allows players to draw a new hand by sacrificing a given number\nof points.',
|
||||
@@ -347,6 +359,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
Redraw: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "A player plays a white card into a round.",
|
||||
properties: {
|
||||
@@ -359,6 +372,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
RegisterUser: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "The details to register a new user for a lobby.",
|
||||
properties: {
|
||||
@@ -376,6 +390,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
Reveal: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "A user judges the winning play for a round.",
|
||||
properties: {
|
||||
@@ -390,6 +405,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
SetHandSize: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "Set the hand size for the lobby.",
|
||||
properties: {
|
||||
@@ -411,6 +427,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
SetPassword: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "Set (or unset) the password for the lobby.",
|
||||
properties: {
|
||||
@@ -432,6 +449,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
SetPublic: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "Set (or unset) the password for the lobby.",
|
||||
properties: {
|
||||
@@ -451,6 +469,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
SetScoreLimit: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "(Un)Set the score limit for the lobby.",
|
||||
properties: {
|
||||
@@ -473,6 +492,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
StartGame: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "Start a game in the lobby if possible.",
|
||||
properties: {
|
||||
@@ -484,6 +504,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
Submit: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "A player plays a white card into a round.",
|
||||
properties: {
|
||||
@@ -502,6 +523,7 @@ export const Schema = {
|
||||
type: "object"
|
||||
},
|
||||
TakeBack: {
|
||||
additionalProperties: false,
|
||||
defaultProperties: [],
|
||||
description: "A player plays a white card into a round.",
|
||||
properties: {
|
||||
|
||||
Reference in New Issue
Block a user