diff --git a/app/assets/stylesheets/lobby.less b/app/assets/stylesheets/lobby.less index 7e162f6..e9c5cc6 100644 --- a/app/assets/stylesheets/lobby.less +++ b/app/assets/stylesheets/lobby.less @@ -290,7 +290,17 @@ ol.played { } } -body.hide-scores { +.hide-scores { + #scores { + transform: translate(0px); + } + + #warning-drawer { + @media (min-width: @enhance-width) { + left: 0px; + } + } + .badge { display: inline-block !important; } @@ -310,8 +320,18 @@ body.hide-scores { transform: translate(@sidebar-width); } + &.shownAsOverlay { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + } + &-title { - padding-left: 20px; + display: flex; + justify-content: space-between; + padding: 0px 5px 0px 5px; } &.active { @@ -366,12 +386,6 @@ body.hide-scores { text-align: center; } -body.hide-scores { - #scores { - transform: translate(0px); - } -} - #warning-drawer { position: fixed; bottom: 0px; @@ -444,14 +458,6 @@ body.hide-scores { } } -body.hide-scores { - #warning-drawer { - @media (min-width: @enhance-width) { - left: 0px; - } - } -} - #history { position: relative; margin: 0px; diff --git a/app/assets/stylesheets/massivedecks.less b/app/assets/stylesheets/massivedecks.less index ce7f9aa..ee8e532 100644 --- a/app/assets/stylesheets/massivedecks.less +++ b/app/assets/stylesheets/massivedecks.less @@ -82,7 +82,7 @@ header { } } -body.hide-scores { +.hide-scores { @media (min-width: @enhance-width) { header { left: 0; diff --git a/app/assets/stylesheets/variables.less b/app/assets/stylesheets/variables.less index 638ed0a..e643153 100644 --- a/app/assets/stylesheets/variables.less +++ b/app/assets/stylesheets/variables.less @@ -1,6 +1,6 @@ @background-color: #e5e5e5; -@enhance-width: 768px; +@enhance-width: 768px; // If changed, should be changed in the elm (Lobby.elm) too. @sidebar-width: 200px; @sidebar-transition-time: 0.2s; diff --git a/app/views/massivedecks/index.scala.html b/app/views/massivedecks/index.scala.html index 6e96047..aa2a981 100644 --- a/app/views/massivedecks/index.scala.html +++ b/app/views/massivedecks/index.scala.html @@ -2,9 +2,6 @@ @head("Massive Decks", url) - [ 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 diff --git a/client/src/MassiveDecks/Scenes/Lobby.elm b/client/src/MassiveDecks/Scenes/Lobby.elm index ba8d877..6f39b4a 100644 --- a/client/src/MassiveDecks/Scenes/Lobby.elm +++ b/client/src/MassiveDecks/Scenes/Lobby.elm @@ -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 diff --git a/client/src/MassiveDecks/Scenes/Lobby/Messages.elm b/client/src/MassiveDecks/Scenes/Lobby/Messages.elm index 7561dd9..a692b7f 100644 --- a/client/src/MassiveDecks/Scenes/Lobby/Messages.elm +++ b/client/src/MassiveDecks/Scenes/Lobby/Messages.elm @@ -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 diff --git a/client/src/MassiveDecks/Scenes/Lobby/Models.elm b/client/src/MassiveDecks/Scenes/Lobby/Models.elm index be3a5b8..bb022a3 100644 --- a/client/src/MassiveDecks/Scenes/Lobby/Models.elm +++ b/client/src/MassiveDecks/Scenes/Lobby/Models.elm @@ -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 } diff --git a/client/src/MassiveDecks/Scenes/Lobby/Sidebar.elm b/client/src/MassiveDecks/Scenes/Lobby/Sidebar.elm new file mode 100644 index 0000000..19f51fd --- /dev/null +++ b/client/src/MassiveDecks/Scenes/Lobby/Sidebar.elm @@ -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) diff --git a/client/src/MassiveDecks/Scenes/Lobby/UI.elm b/client/src/MassiveDecks/Scenes/Lobby/UI.elm index 1922fb4..1926618 100644 --- a/client/src/MassiveDecks/Scenes/Lobby/UI.elm +++ b/client/src/MassiveDecks/Scenes/Lobby/UI.elm @@ -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) diff --git a/client/src/MassiveDecks/Util.elm b/client/src/MassiveDecks/Util.elm index 859eb5e..f7b0d92 100644 --- a/client/src/MassiveDecks/Util.elm +++ b/client/src/MassiveDecks/Util.elm @@ -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 diff --git a/elm-package.json b/elm-package.json index 1501b28..9a46750 100644 --- a/elm-package.json +++ b/elm-package.json @@ -12,6 +12,7 @@ "elm-lang/core": "4.0.0 <= v < 5.0.0", "elm-lang/html": "1.0.0 <= v < 2.0.0", "elm-lang/websocket": "1.0.0 <= v < 2.0.0", + "elm-lang/window": "1.0.0 <= v < 2.0.0", "evancz/elm-http": "3.0.1 <= v < 4.0.0" }, "elm-version": "0.17.0 <= v < 0.18.0" diff --git a/public/javascripts/MassiveDecks.js b/public/javascripts/MassiveDecks.js index c04a594..5ac376b 100644 --- a/public/javascripts/MassiveDecks.js +++ b/public/javascripts/MassiveDecks.js @@ -7320,6 +7320,23 @@ var _elm_lang$html$Html_Events$Options = F2( return {stopPropagation: a, preventDefault: b}; }); +var _Lattyware$massivedecks$MassiveDecks_Util$ifIdDecoder = A2( + _elm_lang$core$Json_Decode$at, + _elm_lang$core$Native_List.fromArray( + ['target', 'id']), + _elm_lang$core$Json_Decode$string); +var _Lattyware$massivedecks$MassiveDecks_Util$onClickIfId = F3( + function (targetId, message, noOp) { + return A2( + _elm_lang$html$Html_Events$on, + 'click', + A2( + _elm_lang$core$Json_Decode$map, + function (clickedId) { + return _elm_lang$core$Native_Utils.eq(clickedId, targetId) ? message : noOp; + }, + _Lattyware$massivedecks$MassiveDecks_Util$ifIdDecoder)); + }); var _Lattyware$massivedecks$MassiveDecks_Util$onKeyDown = F3( function (key, message, noOp) { return A2( @@ -8880,23 +8897,6 @@ var _Lattyware$massivedecks$MassiveDecks_Components_Errors$New = F2( return {ctor: 'New', _0: a, _1: b}; }); -var _Lattyware$massivedecks$MassiveDecks_Components_Overlay$ifIdDecoder = A2( - _elm_lang$core$Json_Decode$at, - _elm_lang$core$Native_List.fromArray( - ['target', 'id']), - _elm_lang$core$Json_Decode$string); -var _Lattyware$massivedecks$MassiveDecks_Components_Overlay$onClickIfId = F3( - function (targetId, message, noOp) { - return A2( - _elm_lang$html$Html_Events$on, - 'click', - A2( - _elm_lang$core$Json_Decode$map, - function (clickedId) { - return _elm_lang$core$Native_Utils.eq(clickedId, targetId) ? message : noOp; - }, - _Lattyware$massivedecks$MassiveDecks_Components_Overlay$ifIdDecoder)); - }); var _Lattyware$massivedecks$MassiveDecks_Components_Overlay$update = F2( function (message, model) { var _p0 = message; @@ -8940,7 +8940,7 @@ var _Lattyware$massivedecks$MassiveDecks_Components_Overlay$view = function (mod [ _elm_lang$html$Html_Attributes$id('mui-overlay'), A3( - _Lattyware$massivedecks$MassiveDecks_Components_Overlay$onClickIfId, + _Lattyware$massivedecks$MassiveDecks_Util$onClickIfId, 'mui-overlay', model.wrap(_Lattyware$massivedecks$MassiveDecks_Components_Overlay$Hide), model.wrap(_Lattyware$massivedecks$MassiveDecks_Components_Overlay$NoOp)), @@ -9081,6 +9081,220 @@ var _Lattyware$massivedecks$MassiveDecks_Models_Notification$playerLeft = F2( return A4(_Lattyware$massivedecks$MassiveDecks_Models_Notification$playerFromIdAndPlayers, id, players, 'sign-out', ' has left the game.'); }); +var _elm_lang$dom$Native_Dom = function() { + +function on(node) +{ + return function(eventName, decoder, toTask) + { + return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) { + + function performTask(event) + { + var result = A2(_elm_lang$core$Json_Decode$decodeValue, decoder, event); + if (result.ctor === 'Ok') + { + _elm_lang$core$Native_Scheduler.rawSpawn(toTask(result._0)); + } + } + + node.addEventListener(eventName, performTask); + + return function() + { + node.removeEventListener(eventName, performTask); + }; + }); + }; +} + +return { + onDocument: F3(on(document)), + onWindow: F3(on(window)) +}; + +}(); + +var _elm_lang$dom$Dom_LowLevel$onWindow = _elm_lang$dom$Native_Dom.onWindow; +var _elm_lang$dom$Dom_LowLevel$onDocument = _elm_lang$dom$Native_Dom.onDocument; + +var _elm_lang$window$Native_Window = function() +{ + +var size = _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) { + callback(_elm_lang$core$Native_Scheduler.succeed({ + width: window.innerWidth, + height: window.innerHeight + })); +}); + +return { + size: size +}; + +}(); +var _elm_lang$window$Window_ops = _elm_lang$window$Window_ops || {}; +_elm_lang$window$Window_ops['&>'] = F2( + function (t1, t2) { + return A2( + _elm_lang$core$Task$andThen, + t1, + function (_p0) { + return t2; + }); + }); +var _elm_lang$window$Window$onSelfMsg = F3( + function (router, dimensions, state) { + var _p1 = state; + if (_p1.ctor === 'Nothing') { + return _elm_lang$core$Task$succeed(state); + } else { + var send = function (_p2) { + var _p3 = _p2; + return A2( + _elm_lang$core$Platform$sendToApp, + router, + _p3._0(dimensions)); + }; + return A2( + _elm_lang$window$Window_ops['&>'], + _elm_lang$core$Task$sequence( + A2(_elm_lang$core$List$map, send, _p1._0.subs)), + _elm_lang$core$Task$succeed(state)); + } + }); +var _elm_lang$window$Window$init = _elm_lang$core$Task$succeed(_elm_lang$core$Maybe$Nothing); +var _elm_lang$window$Window$size = _elm_lang$window$Native_Window.size; +var _elm_lang$window$Window$width = A2( + _elm_lang$core$Task$map, + function (_) { + return _.width; + }, + _elm_lang$window$Window$size); +var _elm_lang$window$Window$height = A2( + _elm_lang$core$Task$map, + function (_) { + return _.height; + }, + _elm_lang$window$Window$size); +var _elm_lang$window$Window$onEffects = F3( + function (router, newSubs, oldState) { + var _p4 = {ctor: '_Tuple2', _0: oldState, _1: newSubs}; + if (_p4._0.ctor === 'Nothing') { + if (_p4._1.ctor === '[]') { + return _elm_lang$core$Task$succeed(_elm_lang$core$Maybe$Nothing); + } else { + return A2( + _elm_lang$core$Task$andThen, + _elm_lang$core$Process$spawn( + A3( + _elm_lang$dom$Dom_LowLevel$onWindow, + 'resize', + _elm_lang$core$Json_Decode$succeed( + {ctor: '_Tuple0'}), + function (_p5) { + return A2( + _elm_lang$core$Task$andThen, + _elm_lang$window$Window$size, + _elm_lang$core$Platform$sendToSelf(router)); + })), + function (pid) { + return _elm_lang$core$Task$succeed( + _elm_lang$core$Maybe$Just( + {subs: newSubs, pid: pid})); + }); + } + } else { + if (_p4._1.ctor === '[]') { + return A2( + _elm_lang$window$Window_ops['&>'], + _elm_lang$core$Process$kill(_p4._0._0.pid), + _elm_lang$core$Task$succeed(_elm_lang$core$Maybe$Nothing)); + } else { + return _elm_lang$core$Task$succeed( + _elm_lang$core$Maybe$Just( + {subs: newSubs, pid: _p4._0._0.pid})); + } + } + }); +var _elm_lang$window$Window$subscription = _elm_lang$core$Native_Platform.leaf('Window'); +var _elm_lang$window$Window$Size = F2( + function (a, b) { + return {width: a, height: b}; + }); +var _elm_lang$window$Window$MySub = function (a) { + return {ctor: 'MySub', _0: a}; +}; +var _elm_lang$window$Window$resizes = function (tagger) { + return _elm_lang$window$Window$subscription( + _elm_lang$window$Window$MySub(tagger)); +}; +var _elm_lang$window$Window$subMap = F2( + function (func, _p6) { + var _p7 = _p6; + return _elm_lang$window$Window$MySub( + function (_p8) { + return func( + _p7._0(_p8)); + }); + }); +_elm_lang$core$Native_Platform.effectManagers['Window'] = {pkg: 'elm-lang/window', init: _elm_lang$window$Window$init, onEffects: _elm_lang$window$Window$onEffects, onSelfMsg: _elm_lang$window$Window$onSelfMsg, tag: 'sub', subMap: _elm_lang$window$Window$subMap}; + +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$init = function (enhanceWidth) { + return {enhanceWidth: enhanceWidth, hidden: false, shownAsOverlay: false}; +}; +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$Model = F3( + function (a, b, c) { + return {enhanceWidth: a, hidden: b, shownAsOverlay: c}; + }); +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$Hide = {ctor: 'Hide'}; +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$Show = function (a) { + return {ctor: 'Show', _0: a}; +}; +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$update = F2( + function (message, model) { + var _p0 = message; + switch (_p0.ctor) { + case 'Toggle': + return { + ctor: '_Tuple2', + _0: model, + _1: A3(_elm_lang$core$Task$perform, _Lattyware$massivedecks$MassiveDecks_Util$impossible, _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$Show, _elm_lang$window$Window$width) + }; + case 'Show': + return model.shownAsOverlay ? { + ctor: '_Tuple2', + _0: _elm_lang$core$Native_Utils.update( + model, + {shownAsOverlay: false}), + _1: _elm_lang$core$Platform_Cmd$none + } : ((_elm_lang$core$Native_Utils.cmp(_p0._0, model.enhanceWidth) > 0) ? { + ctor: '_Tuple2', + _0: _elm_lang$core$Native_Utils.update( + model, + { + hidden: _elm_lang$core$Basics$not(model.hidden) + }), + _1: _elm_lang$core$Platform_Cmd$none + } : { + ctor: '_Tuple2', + _0: _elm_lang$core$Native_Utils.update( + model, + {shownAsOverlay: true}), + _1: _elm_lang$core$Platform_Cmd$none + }); + default: + return { + ctor: '_Tuple2', + _0: _elm_lang$core$Native_Utils.update( + model, + {shownAsOverlay: false}), + _1: _elm_lang$core$Platform_Cmd$none + }; + } + }); +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$Toggle = {ctor: 'Toggle'}; + var _Lattyware$massivedecks$MassiveDecks_Scenes_Config_Messages$LocalMessage = function (a) { return {ctor: 'LocalMessage', _0: a}; }; @@ -9289,6 +9503,9 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$OverlayMessage = var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$ErrorMessage = function (a) { return {ctor: 'ErrorMessage', _0: a}; }; +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$SidebarMessage = function (a) { + return {ctor: 'SidebarMessage', _0: a}; +}; var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$PlayingMessage = function (a) { return {ctor: 'PlayingMessage', _0: a}; }; @@ -9772,10 +9989,27 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Playing_Models$ShownCard = F4( return {rotation: a, horizontalPos: b, isLeft: c, verticalPos: d}; }); -var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Models$Model = F9( - function (a, b, c, d, e, f, g, h, i) { - return {lobby: a, hand: b, config: c, playing: d, browserNotifications: e, secret: f, init: g, notification: h, qrNeedsRendering: i}; - }); +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Models$Model = function (a) { + return function (b) { + return function (c) { + return function (d) { + return function (e) { + return function (f) { + return function (g) { + return function (h) { + return function (i) { + return function (j) { + return {lobby: a, hand: b, config: c, playing: d, browserNotifications: e, secret: f, init: g, notification: h, qrNeedsRendering: i, sidebar: j}; + }; + }; + }; + }; + }; + }; + }; + }; + }; +}; var _Lattyware$massivedecks$MassiveDecks_Scenes_Start_Models$Model = F9( function (a, b, c, d, e, f, g, h, i) { @@ -14948,21 +15182,20 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$notificationPopup = fun ]); } }; -var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$scoresButton = function (shown) { - var showHideClasses = shown ? ' mui--hidden-xs js-hide-scores' : ' mui--visible-xs-inline-block js-show-scores'; - return A2( - _elm_lang$html$Html$button, - _elm_lang$core$Native_List.fromArray( - [ - _elm_lang$html$Html_Attributes$class( - A2(_elm_lang$core$Basics_ops['++'], 'scores-toggle mui-btn mui-btn--small mui-btn--primary badged', showHideClasses)), - _elm_lang$html$Html_Attributes$title('Players.') - ]), - _elm_lang$core$Native_List.fromArray( - [ - _Lattyware$massivedecks$MassiveDecks_Components_Icon$fwIcon('users') - ])); -}; +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$scoresButton = A2( + _elm_lang$html$Html$button, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$class('scores-toggle mui-btn mui-btn--small mui-btn--primary badged'), + _elm_lang$html$Html_Attributes$title('Players.'), + _elm_lang$html$Html_Events$onClick( + _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage( + _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$SidebarMessage(_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$Toggle))) + ]), + _elm_lang$core$Native_List.fromArray( + [ + _Lattyware$massivedecks$MassiveDecks_Components_Icon$fwIcon('users') + ])); var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$appHeader = F2( function (contents, model) { return A2( @@ -14994,12 +15227,9 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$appHeader = F2( _elm_lang$html$Html_Attributes$class('score-buttons') ]), A2( - _elm_lang$core$List$append, + _elm_lang$core$Basics_ops['++'], _elm_lang$core$Native_List.fromArray( - [ - _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$scoresButton(true), - _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$scoresButton(false) - ]), + [_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$scoresButton]), _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$notificationPopup(model.notification))), A2( _elm_lang$html$Html$span, @@ -15077,96 +15307,144 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$score = function (playe ])) ])); }; -var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$scores = function (players) { - return A2( - _elm_lang$html$Html$div, - _elm_lang$core$Native_List.fromArray( - [ - _elm_lang$html$Html_Attributes$id('scores') - ]), - _elm_lang$core$Native_List.fromArray( +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$scores = F2( + function (shownAsOverlay, players) { + var hideMessage = _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage( + _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$SidebarMessage(_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$Hide)); + var closeLink = shownAsOverlay ? _elm_lang$core$Native_List.fromArray( [ A2( - _elm_lang$html$Html$div, + _elm_lang$html$Html$a, _elm_lang$core$Native_List.fromArray( [ - _elm_lang$html$Html_Attributes$id('scores-title'), - _elm_lang$html$Html_Attributes$class('mui--appbar-line-height mui--text-title') + _elm_lang$html$Html_Attributes$class('link close-link'), + _elm_lang$html$Html_Attributes$title('Hide.'), + A2(_elm_lang$html$Html_Attributes$attribute, 'tabindex', '0'), + A2(_elm_lang$html$Html_Attributes$attribute, 'role', 'button'), + _elm_lang$html$Html_Events$onClick(hideMessage) ]), _elm_lang$core$Native_List.fromArray( [ - _elm_lang$html$Html$text('Players') - ])), - A2( - _elm_lang$html$Html$div, - _elm_lang$core$Native_List.fromArray( - [ - _elm_lang$html$Html_Attributes$class('mui-divider') - ]), - _elm_lang$core$Native_List.fromArray( - [])), - A2( - _elm_lang$html$Html$table, - _elm_lang$core$Native_List.fromArray( - [ - _elm_lang$html$Html_Attributes$class('mui-table') - ]), - _elm_lang$core$Native_List.fromArray( - [ - A2( - _elm_lang$html$Html$thead, - _elm_lang$core$Native_List.fromArray( - []), + _Lattyware$massivedecks$MassiveDecks_Components_Icon$icon('times') + ])) + ]) : _elm_lang$core$Native_List.fromArray( + []); + var sidebar = A2( + _elm_lang$html$Html$div, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$id('scores'), + _elm_lang$html$Html_Attributes$classList( + _elm_lang$core$Native_List.fromArray( + [ + {ctor: '_Tuple2', _0: 'shownAsOverlay', _1: shownAsOverlay} + ])) + ]), + _elm_lang$core$Native_List.fromArray( + [ + A2( + _elm_lang$html$Html$div, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$id('scores-title'), + _elm_lang$html$Html_Attributes$class('mui--appbar-line-height mui--text-headline') + ]), + A2( + _elm_lang$core$Basics_ops['++'], _elm_lang$core$Native_List.fromArray( [ - A2( - _elm_lang$html$Html$tr, - _elm_lang$core$Native_List.fromArray( - []), - _elm_lang$core$Native_List.fromArray( - [ - A2( - _elm_lang$html$Html$th, - _elm_lang$core$Native_List.fromArray( - [ - _elm_lang$html$Html_Attributes$class('state'), - _elm_lang$html$Html_Attributes$title('State') - ]), - _elm_lang$core$Native_List.fromArray( - [ - _Lattyware$massivedecks$MassiveDecks_Components_Icon$icon('tasks') - ])), - A2( - _elm_lang$html$Html$th, - _elm_lang$core$Native_List.fromArray( - [ - _elm_lang$html$Html_Attributes$class('name') - ]), - _elm_lang$core$Native_List.fromArray( - [ - _elm_lang$html$Html$text('Player') - ])), - A2( - _elm_lang$html$Html$th, - _elm_lang$core$Native_List.fromArray( - [ - _elm_lang$html$Html_Attributes$class('score'), - _elm_lang$html$Html_Attributes$title('Score') - ]), - _elm_lang$core$Native_List.fromArray( - [ - _Lattyware$massivedecks$MassiveDecks_Components_Icon$icon('star') - ])) - ])) - ])), - A2( - _elm_lang$html$Html$tbody, - _elm_lang$core$Native_List.fromArray( - []), - A2(_elm_lang$core$List$map, _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$score, players)) - ])) - ])); -}; + _elm_lang$html$Html$text('Players') + ]), + closeLink)), + A2( + _elm_lang$html$Html$div, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$class('mui-divider') + ]), + _elm_lang$core$Native_List.fromArray( + [])), + A2( + _elm_lang$html$Html$table, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$class('mui-table') + ]), + _elm_lang$core$Native_List.fromArray( + [ + A2( + _elm_lang$html$Html$thead, + _elm_lang$core$Native_List.fromArray( + []), + _elm_lang$core$Native_List.fromArray( + [ + A2( + _elm_lang$html$Html$tr, + _elm_lang$core$Native_List.fromArray( + []), + _elm_lang$core$Native_List.fromArray( + [ + A2( + _elm_lang$html$Html$th, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$class('state'), + _elm_lang$html$Html_Attributes$title('State') + ]), + _elm_lang$core$Native_List.fromArray( + [ + _Lattyware$massivedecks$MassiveDecks_Components_Icon$icon('tasks') + ])), + A2( + _elm_lang$html$Html$th, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$class('name') + ]), + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html$text('Player') + ])), + A2( + _elm_lang$html$Html$th, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$class('score'), + _elm_lang$html$Html_Attributes$title('Score') + ]), + _elm_lang$core$Native_List.fromArray( + [ + _Lattyware$massivedecks$MassiveDecks_Components_Icon$icon('star') + ])) + ])) + ])), + A2( + _elm_lang$html$Html$tbody, + _elm_lang$core$Native_List.fromArray( + []), + A2(_elm_lang$core$List$map, _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$score, players)) + ])) + ])); + return shownAsOverlay ? A2( + _elm_lang$html$Html$div, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$id('mui-overlay'), + A3( + _Lattyware$massivedecks$MassiveDecks_Util$onClickIfId, + 'mui-overlay', + hideMessage, + _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage(_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$NoOp)), + A3( + _Lattyware$massivedecks$MassiveDecks_Util$onKeyDown, + 'Escape', + hideMessage, + _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage(_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$NoOp)), + _elm_lang$html$Html_Attributes$tabindex(0) + ]), + _elm_lang$core$Native_List.fromArray( + [sidebar])) : sidebar; + }); var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$spacer = A2( _elm_lang$html$Html$div, _elm_lang$core$Native_List.fromArray( @@ -15184,15 +15462,21 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$contentWrapper = functi ]), contents); }; -var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$root = function (contents) { - return A2( - _elm_lang$html$Html$div, - _elm_lang$core$Native_List.fromArray( - [ - _elm_lang$html$Html_Attributes$class('content') - ]), - contents); -}; +var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$root = F2( + function (hideScores, contents) { + return A2( + _elm_lang$html$Html$div, + _elm_lang$core$Native_List.fromArray( + [ + _elm_lang$html$Html_Attributes$classList( + _elm_lang$core$Native_List.fromArray( + [ + {ctor: '_Tuple2', _0: 'content', _1: true}, + {ctor: '_Tuple2', _0: 'hide-scores', _1: hideScores} + ])) + ]), + contents); + }); var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$view = function (model) { var url = model.init.url; var lobby = model.lobby; @@ -15243,12 +15527,14 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$view = function (model) }(); var header = _p6._0; var contents = _p6._1; - return _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$root( + return A2( + _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$root, + model.sidebar.hidden, _elm_lang$core$Native_List.fromArray( [ A2(_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$appHeader, header, model), _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$spacer, - _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$scores(players), + A2(_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$scores, model.sidebar.shownAsOverlay, players), _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_UI$contentWrapper(contents) ])); }; @@ -15725,11 +16011,28 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby$update = F2( cmd) }; } + case 'SidebarMessage': + var _p27 = A2(_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$update, _p20._0, model.sidebar); + var sidebarModel = _p27._0; + var cmd = _p27._1; + return { + ctor: '_Tuple2', + _0: _elm_lang$core$Native_Utils.update( + model, + {sidebar: sidebarModel}), + _1: A2( + _elm_lang$core$Platform_Cmd$map, + function (_p28) { + return _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage( + _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$SidebarMessage(_p28)); + }, + cmd) + }; case 'BrowserNotificationsMessage': - var _p27 = A2(_Lattyware$massivedecks$MassiveDecks_Components_BrowserNotifications$update, _p20._0, model.browserNotifications); - var browserNotifications = _p27._0; - var localCmd = _p27._1; - var cmd = _p27._2; + var _p29 = A2(_Lattyware$massivedecks$MassiveDecks_Components_BrowserNotifications$update, _p20._0, model.browserNotifications); + var browserNotifications = _p29._0; + var localCmd = _p29._1; + var cmd = _p29._2; return A2( _elm_lang$core$Platform_Cmd_ops['!'], _elm_lang$core$Native_Utils.update( @@ -15739,18 +16042,18 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby$update = F2( [ A2( _elm_lang$core$Platform_Cmd$map, - function (_p28) { + function (_p30) { return _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage( - _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$BrowserNotificationsMessage(_p28)); + _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$BrowserNotificationsMessage(_p30)); }, localCmd), A2(_elm_lang$core$Platform_Cmd$map, _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby$overlayAlert, cmd) ])); case 'BrowserNotificationForUser': var cmd = function () { - var _p29 = _p20._0(lobby); - if (_p29.ctor === 'Just') { - return _elm_lang$core$Native_Utils.eq(_p29._0, model.secret.id) ? _Lattyware$massivedecks$MassiveDecks_Util$cmd( + var _p31 = _p20._0(lobby); + if (_p31.ctor === 'Just') { + return _elm_lang$core$Native_Utils.eq(_p31._0, model.secret.id) ? _Lattyware$massivedecks$MassiveDecks_Util$cmd( _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage( _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$BrowserNotificationsMessage( _Lattyware$massivedecks$MassiveDecks_Components_BrowserNotifications$notify( @@ -15838,9 +16141,9 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby$update = F2( model, A2( _elm_lang$core$List$map, - function (_p30) { + function (_p32) { return _Lattyware$massivedecks$MassiveDecks_Util$cmd( - _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage(_p30)); + _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage(_p32)); }, _p20._0)); default: @@ -15851,7 +16154,7 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby$subscriptions = function ( var render = model.qrNeedsRendering ? _elm_lang$core$Native_List.fromArray( [ _elm_lang$animation_frame$AnimationFrame$diffs( - function (_p31) { + function (_p33) { return _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$LocalMessage(_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$RenderQr); }) ]) : _elm_lang$core$Native_List.fromArray( @@ -15865,8 +16168,8 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby$subscriptions = function ( A2(_Lattyware$massivedecks$MassiveDecks_Scenes_Lobby$webSocketUrl, model.init.url, model.lobby.gameCode), _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby$webSocketResponseDecoder); var delegated = function () { - var _p32 = model.lobby.round; - if (_p32.ctor === 'Nothing') { + var _p34 = model.lobby.round; + if (_p34.ctor === 'Nothing') { return A2( _elm_lang$core$Platform_Sub$map, _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Messages$ConfigMessage, @@ -15902,7 +16205,8 @@ var _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby$init = F3( secret: secret, init: init, notification: _elm_lang$core$Maybe$Nothing, - qrNeedsRendering: false + qrNeedsRendering: false, + sidebar: _Lattyware$massivedecks$MassiveDecks_Scenes_Lobby_Sidebar$init(768) }, _elm_lang$core$Native_List.fromArray( [])); diff --git a/public/javascripts/util.js b/public/javascripts/util.js index bb7add8..0829b22 100644 --- a/public/javascripts/util.js +++ b/public/javascripts/util.js @@ -1,26 +1,5 @@ -jQuery(function($) { - var $bodyEl = $('body'); - - function showScores() { - var scores = $('#scores')[0].cloneNode(true); - - mui.overlay('on', scores); - - setTimeout(function() { - $(scores).addClass('active'); - }, 20); - } - - function hideScores() { - $bodyEl.toggleClass('hide-scores'); - } - - $('body').on('click', '.js-show-scores', showScores); - $('body').on('click', '.js-hide-scores', hideScores); -}); - function toggleWarningDrawer() { - $('#warning-drawer').toggleClass('shut'); + document.getElementById('#warning-drawer').classList.toggle('shut'); } function start(url) { @@ -46,15 +25,15 @@ function start(url) { game.ports.existingGame.subscribe(function (gameCodeAndSecret) { if (gameCodeAndSecret != null) { localStorage.setItem("existing-game", JSON.stringify(gameCodeAndSecret)) - window.location = "#" + gameCodeAndSecret.gameCode; + window.history.replaceState(null, "", "/#" + gameCodeAndSecret.gameCode); } else { - window.location = "#"; + window.history.replaceState(null, "", "/"); localStorage.removeItem("existing-game"); } }); game.ports.qr.subscribe(function (idAndValue) { - new QRCode($('#' + idAndValue.id)[0], { + new QRCode(document.getElementById('#' + idAndValue.id), { text: idAndValue.value, width: 200, height: 200