Move the sidebar state into elm for consistency and simplicity.

This commit is contained in:
Gareth Latty
2016-06-26 23:51:18 +01:00
parent 48ff42a5b4
commit d95c558cc8
14 changed files with 614 additions and 233 deletions
+1 -10
View File
@@ -68,7 +68,7 @@ view model =
case model.overlay of
Just overlay ->
[ div [ id "mui-overlay"
, onClickIfId "mui-overlay" (model.wrap Hide) (model.wrap NoOp)
, Util.onClickIfId "mui-overlay" (model.wrap Hide) (model.wrap NoOp)
, Util.onKeyDown "Escape" (model.wrap Hide) (model.wrap NoOp)
, tabindex 0
]
@@ -87,12 +87,3 @@ view model =
]
Nothing ->
[]
onClickIfId : String -> msg -> msg -> Attribute msg
onClickIfId targetId message noOp =
on "click" (ifIdDecoder |> Json.map (\clickedId -> if clickedId == targetId then message else noOp))
ifIdDecoder : Json.Decoder String
ifIdDecoder = Json.at [ "target", "id" ] Json.string
+8
View File
@@ -29,6 +29,7 @@ import MassiveDecks.Scenes.Config.Messages as Config
import MassiveDecks.Scenes.Lobby.UI as UI
import MassiveDecks.Scenes.Lobby.Messages exposing (ConsumerMessage(..), Message(..))
import MassiveDecks.Scenes.Lobby.Models exposing (Model)
import MassiveDecks.Scenes.Lobby.Sidebar as Sidebar
import MassiveDecks.Util as Util exposing ((:>))
@@ -45,6 +46,7 @@ init init lobbyAndHand secret =
, init = init
, notification = Nothing
, qrNeedsRendering = False
, sidebar = Sidebar.init 768 {- Should match the enhance-width in less. -}
} ! []
@@ -146,6 +148,12 @@ update message model =
in
({ model | playing = playing }, Cmd.map (LocalMessage << PlayingMessage) cmd)
SidebarMessage sidebarMessage ->
let
(sidebarModel, cmd) = Sidebar.update sidebarMessage model.sidebar
in
({ model | sidebar = sidebarModel }, Cmd.map (LocalMessage << SidebarMessage) cmd)
BrowserNotificationsMessage notificationMessage ->
let
(browserNotifications, localCmd, cmd) = BrowserNotifications.update notificationMessage model.browserNotifications
@@ -4,6 +4,7 @@ import MassiveDecks.Models.Game as Game
import MassiveDecks.Models.Card as Card
import MassiveDecks.Models.Player as Player exposing (Player)
import MassiveDecks.Models.Notification as Notification exposing (Notification)
import MassiveDecks.Scenes.Lobby.Sidebar as Sidebar
import MassiveDecks.Scenes.Config.Messages as Config
import MassiveDecks.Scenes.Playing.Messages as Playing
import MassiveDecks.Components.Errors as Errors
@@ -37,3 +38,4 @@ type Message
| BrowserNotificationsMessage BrowserNotifications.Message
| ConfigMessage Config.ConsumerMessage
| PlayingMessage Playing.ConsumerMessage
| SidebarMessage Sidebar.Message
@@ -5,6 +5,7 @@ import MassiveDecks.Models.Game as Game
import MassiveDecks.Models.Player as Player
import MassiveDecks.Models.Card as Card
import MassiveDecks.Models.Notification as Notification exposing (Notification)
import MassiveDecks.Scenes.Lobby.Sidebar as Sidebar
import MassiveDecks.Scenes.Config.Models as Config
import MassiveDecks.Scenes.Playing.Models as Playing
import MassiveDecks.Components.BrowserNotifications as BrowserNotifications
@@ -22,4 +23,5 @@ type alias Model =
, init : Init
, notification : Maybe Notification
, qrNeedsRendering : Bool
, sidebar : Sidebar.Model
}
@@ -0,0 +1,54 @@
port module MassiveDecks.Scenes.Lobby.Sidebar exposing (Model, Message(..), init, update)
import Task
import Window
import MassiveDecks.Util as Util
{-| This component handles the players sidebar for the lobby view. On a larger display, this bar is shown, but can be
hidden by the user. On small displays, it is hidden but can be popped out as a modal window over the top of the
lobby.
No rendering is done within this module - instead the model should be inspected and the sidebar rendered as required.
-}
type alias Model =
{ enhanceWidth : Int
, hidden : Bool
, shownAsOverlay : Bool
}
type Message
= Toggle
| Show Int
| Hide
init : Int -> Model
init enhanceWidth =
{ enhanceWidth = enhanceWidth
, hidden = False
, shownAsOverlay = False
}
update : Message -> Model -> (Model, Cmd Message)
update message model =
case message of
Toggle ->
(model, Task.perform Util.impossible Show Window.width)
Show screenWidth ->
if model.shownAsOverlay then
({ model | shownAsOverlay = False }, Cmd.none)
else if screenWidth > model.enhanceWidth then
({ model | hidden = not model.hidden }, Cmd.none)
else
({ model | shownAsOverlay = True }, Cmd.none)
Hide ->
({ model | shownAsOverlay = False }, Cmd.none)
+54 -28
View File
@@ -14,6 +14,7 @@ import MassiveDecks.Scenes.Config as Config
import MassiveDecks.Scenes.Playing as Playing
import MassiveDecks.Scenes.Lobby.Models exposing (Model)
import MassiveDecks.Scenes.Lobby.Messages exposing (ConsumerMessage(..), Message(..))
import MassiveDecks.Scenes.Lobby.Sidebar as Sidebar
import MassiveDecks.Models.Player as Player exposing (Player, Status(..))
import MassiveDecks.Models.Notification as Notification exposing (Notification)
import MassiveDecks.Util as Util
@@ -34,15 +35,16 @@ view model =
in
(h |> List.map (Html.map (PlayingMessage >> LocalMessage)), c |> List.map (Html.map (PlayingMessage >> LocalMessage)))
in
root [ appHeader header model
, spacer
, scores players
, contentWrapper contents
]
root model.sidebar.hidden
[ appHeader header model
, spacer
, scores model.sidebar.shownAsOverlay players
, contentWrapper contents
]
root : List (Html msg) -> Html msg
root contents = div [ class "content" ] contents
root : Bool -> List (Html msg) -> Html msg
root hideScores contents = div [ classList [ ("content", True), ("hide-scores", hideScores) ] ] contents
contentWrapper : List (Html msg) -> Html msg
@@ -53,19 +55,44 @@ spacer : Html msg
spacer = div [ class "mui--appbar-height" ] []
scores : List Player -> Html msg
scores players = div [ id "scores" ]
[ div [ id "scores-title", class "mui--appbar-line-height mui--text-title" ] [ text "Players" ]
, div [ class "mui-divider" ] []
, table [ class "mui-table" ]
[ thead [] [ tr [] [ th [ class "state", title "State" ] [ Icon.icon "tasks" ]
, th [ class "name" ] [ text "Player" ]
, th [ class "score", title "Score" ] [ Icon.icon "star" ]
]
]
, tbody [] (List.map score players)
]
]
scores : Bool -> List Player -> Html ConsumerMessage
scores shownAsOverlay players =
let
hideMessage = LocalMessage (SidebarMessage Sidebar.Hide)
closeLink = if shownAsOverlay then
[ a [ class "link close-link"
, title "Hide."
, attribute "tabindex" "0"
, attribute "role" "button"
, onClick hideMessage
] [ Icon.icon "times" ]
]
else
[]
sidebar =
div [ id "scores", classList [ ("shownAsOverlay", shownAsOverlay) ] ]
[ div [ id "scores-title", class "mui--appbar-line-height mui--text-headline" ] ([ text "Players" ] ++ closeLink)
, div [ class "mui-divider" ] []
, table [ class "mui-table" ]
[ thead [] [ tr [] [ th [ class "state", title "State" ] [ Icon.icon "tasks" ]
, th [ class "name" ] [ text "Player" ]
, th [ class "score", title "Score" ] [ Icon.icon "star" ]
]
]
, tbody [] (List.map score players)
]
]
in
if shownAsOverlay then
div [ id "mui-overlay"
, Util.onClickIfId "mui-overlay" hideMessage (LocalMessage NoOp)
, Util.onKeyDown "Escape" hideMessage (LocalMessage NoOp)
, tabindex 0
]
[ sidebar ]
else
sidebar
score : Player -> Html msg
score player =
@@ -87,19 +114,18 @@ score player =
appHeader : List (Html ConsumerMessage) -> Model -> Html ConsumerMessage
appHeader contents model = (header [] [ div [ class "mui-appbar mui--appbar-line-height" ]
[ div [ class "mui--appbar-line-height" ]
[ span [ class "score-buttons" ] (List.append [ scoresButton True, scoresButton False ] (notificationPopup model.notification))
[ span [ class "score-buttons" ] ([ scoresButton ] ++ (notificationPopup model.notification))
, span [ id "title", class "mui--text-title mui--visible-xs-inline-block" ] contents
, gameMenu model ] ] ])
scoresButton : Bool -> Html msg
scoresButton shown =
let
showHideClasses = if shown then " mui--hidden-xs js-hide-scores" else " mui--visible-xs-inline-block js-show-scores"
in
button [ class ("scores-toggle mui-btn mui-btn--small mui-btn--primary badged" ++ showHideClasses)
scoresButton : Html ConsumerMessage
scoresButton =
button [ class ("scores-toggle mui-btn mui-btn--small mui-btn--primary badged")
, title "Players."
] [ Icon.fwIcon "users" ]
, onClick (LocalMessage (SidebarMessage Sidebar.Toggle))
]
[ Icon.fwIcon "users" ]
notificationPopup : Maybe Notification -> List (Html ConsumerMessage)
+11
View File
@@ -150,3 +150,14 @@ isNothing m =
onKeyDown : String -> msg -> msg -> Attribute msg
onKeyDown key message noOp =
on "keydown" (Json.at [ "key" ] Json.string |> Json.map (\pressed -> if pressed == key then message else noOp))
{-| Perform an action on click, only if the id of the clicked element matches (i.e: only on click for a given element
in the tree).
-}
onClickIfId : String -> msg -> msg -> Attribute msg
onClickIfId targetId message noOp =
on "click" (ifIdDecoder |> Json.map (\clickedId -> if clickedId == targetId then message else noOp))
ifIdDecoder : Json.Decoder String
ifIdDecoder = Json.at [ "target", "id" ] Json.string