Add a built-in deck source and the CaH base deck.

This does a lot of the work needed for #120.
This commit is contained in:
Gareth Latty
2020-05-01 01:12:12 +01:00
parent 3024b9430a
commit 17331589f0
52 changed files with 2450 additions and 301 deletions
+16 -2
View File
@@ -4,6 +4,7 @@ import Browser
import Browser.Navigation as Navigation
import Html exposing (Html)
import Html.Attributes as HtmlA
import Http
import Json.Decode as Json
import MassiveDecks.Cast.Client as Cast
import MassiveDecks.Cast.Model as Cast
@@ -28,6 +29,8 @@ import MassiveDecks.Pages.Route as Route exposing (Route)
import MassiveDecks.Pages.Start as Start
import MassiveDecks.Pages.Start.Route as Start
import MassiveDecks.Pages.Unknown as Unknown
import MassiveDecks.Requests.Api as Api
import MassiveDecks.Requests.Request as Request
import MassiveDecks.ServerConnection as ServerConnection
import MassiveDecks.Settings as Settings
import MassiveDecks.Settings.Messages as Settings
@@ -85,6 +88,7 @@ init flags url key =
, speech = speech
, notifications = Notifications.init
, remoteMode = remoteMode
, sources = { builtIn = Nothing, cardcast = False }
}
( page, pageCmd ) =
@@ -93,9 +97,12 @@ init flags url key =
else
( Pages.Loading, Cmd.none )
sourceCmd =
Request.map (Error.Add >> ErrorMsg) never UpdateSources |> Api.sourceInfo |> Http.request
in
( { page = page, shared = shared, errorOverlay = Overlay.init }
, Cmd.batch [ pageCmd, settingsCmd, speechCmd ]
, Cmd.batch [ sourceCmd, pageCmd, settingsCmd, speechCmd ]
)
@@ -264,6 +271,13 @@ update msg model =
in
( { model | shared = { oldShared | notifications = notifications } }, notificationsCmd )
UpdateSources info ->
let
oldShared =
model.shared
in
( { model | shared = { oldShared | sources = info } }, Cmd.none )
Refresh ->
( model, Navigation.reload )
@@ -284,7 +298,7 @@ update msg model =
Settings.update model.shared (Settings.ChangeLang (Just language))
( lobby, lobbyCmd ) =
Lobby.initWithAuth { gameCode = auth.claims.gc, section = Just Lobby.Spectate } auth
Lobby.initWithAuth shared { gameCode = auth.claims.gc, section = Just Lobby.Spectate } auth
in
( { model
| page = Pages.Lobby lobby
+38 -18
View File
@@ -1,6 +1,7 @@
module MassiveDecks.Card.Parts exposing
( Part(..)
, Parts
, Style(..)
, Transform(..)
, fromList
, map
@@ -19,16 +20,24 @@ import MassiveDecks.Util.String as String
{-| A transform to apply to the value in a slot.
-}
type Transform
= UpperCase
= NoTransform
| UpperCase
| Capitalize
| Stay
{-| A style to be applied to some text.
-}
type Style
= NoStyle
| Em
| Strong
{-| A part of a call's text. This is either just text or a position for a call to be inserted in-game.
-}
type Part
= Text String
| Slot Transform
= Text String Style
| Slot Transform Style
{-| Represents a line as a part of a part. Between each one the text will be forced to line break.
@@ -48,10 +57,10 @@ type Parts
isSlot : Part -> Bool
isSlot part =
case part of
Text _ ->
Text _ _ ->
False
Slot _ ->
Slot _ _ ->
True
@@ -136,18 +145,18 @@ viewLinesString blankPhrase =
viewLines (\s -> \p -> viewPartsString blankPhrase s p |> String.join "")
viewParts : (Bool -> String -> List a) -> a -> List String -> List Part -> List a
viewParts : (Bool -> String -> Style -> List a) -> a -> List String -> List Part -> List a
viewParts viewText emptySlot play parts =
case parts of
firstPart :: restParts ->
case firstPart of
Text string ->
viewText False string ++ viewParts viewText emptySlot play restParts
Text string style ->
viewText False string style ++ viewParts viewText emptySlot play restParts
Slot transform ->
Slot transform style ->
case play of
firstPlay :: restPlay ->
viewText True (applyTransform transform firstPlay) ++ viewParts viewText emptySlot restPlay restParts
viewText True (applyTransform transform firstPlay) style ++ viewParts viewText emptySlot restPlay restParts
[] ->
emptySlot :: viewParts viewText emptySlot [] restParts
@@ -163,27 +172,38 @@ viewPartsHtml =
viewPartsString : String -> List String -> List Part -> List String
viewPartsString blankPhrase =
viewParts (\_ -> \s -> [ s ]) blankPhrase
viewParts (\_ -> \s -> \_ -> [ s ]) blankPhrase
applyTransform : Transform -> String -> String
applyTransform transform value =
case transform of
NoTransform ->
value
UpperCase ->
String.toUpper value
Capitalize ->
String.capitalise value
Stay ->
value
viewTextHtml : Bool -> String -> List (Html msg)
viewTextHtml slot string =
viewTextHtml : Bool -> String -> Style -> List (Html msg)
viewTextHtml slot string style =
let
element =
case style of
NoStyle ->
Html.span
Em ->
Html.em
Strong ->
Html.strong
words =
string |> splitWords |> List.map (\word -> Html.span [] [ Html.text word ])
string |> splitWords |> List.map (\word -> element [] [ Html.text word ])
in
if slot then
[ Html.span [ HtmlA.class "slot" ] words ]
+16 -1
View File
@@ -16,6 +16,7 @@ import MassiveDecks.Model exposing (Shared)
import MassiveDecks.Pages.Lobby.Configure.Decks as Decks
import MassiveDecks.Pages.Lobby.Configure.Model exposing (Config)
import MassiveDecks.Util.String as String
import Regex exposing (Regex)
{-| Render the response to HTML.
@@ -71,9 +72,23 @@ viewCustom shared config side update canonicalize attributes response fill =
{- Private -}
punctuation : Regex
punctuation =
-- TODO: This should probably get localized.
Regex.fromString "[.?!]$" |> Maybe.withDefault Regex.never
viewBody : Response -> ViewBody msg
viewBody response =
ViewBody (\() -> [ Html.p [] [ Html.span [] [ response.body |> String.capitalise |> Html.text ] ] ])
let
end =
if response.body |> Regex.contains punctuation then
[]
else
[ Html.text "." ]
in
ViewBody (\() -> [ Html.p [] [ Html.span [] ((response.body |> String.capitalise |> Html.text) :: end) ] ])
viewCustomBody : String -> (String -> msg) -> (String -> msg) -> String -> Maybe String -> ViewBody msg
+40 -17
View File
@@ -17,6 +17,7 @@ module MassiveDecks.Card.Source exposing
import Html exposing (Html)
import Html.Attributes as HtmlA
import Html.Events as HtmlE
import MassiveDecks.Card.Source.BuiltIn as BuiltIn
import MassiveDecks.Card.Source.Cardcast as Cardcast
import MassiveDecks.Card.Source.Custom as Player
import MassiveDecks.Card.Source.Fake as Fake
@@ -27,15 +28,16 @@ import MassiveDecks.Model exposing (..)
import MassiveDecks.Pages.Lobby.Configure.Decks.Model exposing (DeckOrError)
import MassiveDecks.Strings as Strings exposing (MdString)
import MassiveDecks.Strings.Languages as Lang
import MassiveDecks.Util.Maybe as Maybe
import Weightless as Wl
import Weightless.Attributes as WlA
{-| The default source for an editor.
-}
default : External
default : Shared -> External
default =
Cardcast.generalMethods.empty ()
BuiltIn.generalMethods.empty
{-| Check if two sources are equal.
@@ -57,23 +59,33 @@ externalAndEquals a b =
False
{-| Get an empty source of the given type.
{-| Get an general methods of the given type.
-}
empty : String -> Maybe External
empty n =
generalMethods : String -> Maybe (ExternalGeneralMethods msg)
generalMethods n =
case n of
"BuiltIn" ->
BuiltIn.generalMethods |> Just
"Cardcast" ->
() |> Cardcast.generalMethods.empty |> Just
Cardcast.generalMethods |> Just
_ ->
Nothing
{-| Get an empty source of the given type.
-}
empty : Shared -> String -> Maybe External
empty shared n =
generalMethods n |> Maybe.map (\m -> m.empty shared)
{-| An empty source of the same general type as the given one.
-}
emptyMatching : External -> External
emptyMatching source =
() |> (externalMethods source |> .empty)
emptyMatching : Shared -> External -> External
emptyMatching shared source =
shared |> (externalMethods source |> .empty)
{-| The name of a source.
@@ -99,9 +111,9 @@ defaultDetails shared source =
{-| A tooltip for a source.
-}
tooltip : Source -> Maybe ( String, Html msg )
tooltip source =
case () |> (methods source |> .tooltip) of
tooltip : Shared -> Source -> Maybe ( String, Html msg )
tooltip shared source =
case shared |> (methods source |> .tooltip) of
Just ( id, rendered ) ->
Just
( id
@@ -134,15 +146,23 @@ logo source =
-}
generalEditor : Shared -> List DeckOrError -> External -> (External -> msg) -> List (Html msg)
generalEditor shared existing currentValue update =
let
enabledSources =
[ shared.sources.builtIn |> Maybe.map (\_ -> BuiltIn.generalMethods)
, Cardcast.generalMethods |> Maybe.justIf shared.sources.cardcast
]
toOption source =
Html.option [ HtmlA.value (source.id ()) ]
[ () |> source.name |> Lang.html shared
]
in
[ Wl.select
[ HtmlA.id "source-selector"
, WlA.outlined
, HtmlE.onInput (empty >> Maybe.withDefault default >> update)
]
[ Html.option [ HtmlA.value "Cardcast" ]
[ Strings.Cardcast |> Lang.html shared
]
, HtmlE.onInput (empty shared >> Maybe.withDefault (default shared) >> update)
]
(enabledSources |> List.filterMap (Maybe.map toOption))
, editor shared existing currentValue update
]
@@ -197,3 +217,6 @@ externalMethods external =
case external of
Cardcast playCode ->
Cardcast.methods playCode
BuiltIn id ->
BuiltIn.methods id
@@ -0,0 +1,132 @@
module MassiveDecks.Card.Source.BuiltIn exposing
( generalMethods
, methods
)
import Html as Html exposing (Html)
import Html.Attributes as HtmlA
import Html.Events as HtmlE
import MassiveDecks.Card.Source.BuiltIn.Model exposing (..)
import MassiveDecks.Card.Source.Methods as Source
import MassiveDecks.Card.Source.Model as Source exposing (Source)
import MassiveDecks.Components.Form.Message exposing (Message)
import MassiveDecks.Model exposing (..)
import MassiveDecks.Pages.Lobby.Configure.Decks.Model as Decks exposing (DeckOrError)
import MassiveDecks.Strings as Strings exposing (MdString)
import MassiveDecks.Util.Html as Html
import Weightless as Wl
import Weightless.Attributes as WlA
methods : Id -> Source.ExternalMethods msg
methods given =
{ name = name
, logo = logo
, empty = empty
, id = id
, problems = problems given
, defaultDetails = details given
, tooltip = tooltip given
, editor = editor given
, equals = equals given
}
generalMethods : Source.ExternalGeneralMethods msg
generalMethods =
{ name = name
, logo = logo
, empty = empty
, id = id
}
{- Private -}
id : () -> String
id _ =
"BuiltIn"
name : () -> MdString
name () =
Strings.BuiltIn
empty : Shared -> Source.External
empty shared =
shared.sources.builtIn
|> Maybe.andThen (.decks >> List.head)
|> Maybe.map .id
|> Maybe.withDefault (Id "")
|> Source.BuiltIn
equals : Id -> Source.External -> Bool
equals (Id given) source =
case source of
Source.BuiltIn (Id other) ->
given == other
_ ->
False
problems : Id -> () -> List (Message msg)
problems _ () =
[]
editor : Id -> Shared -> List DeckOrError -> (Source.External -> msg) -> Html msg
editor (Id selectedId) shared _ update =
case shared.sources.builtIn of
Just { decks } ->
let
deck deckInfo =
case deckInfo.id of
Id other ->
Html.option
[ HtmlA.selected (selectedId == other)
, HtmlA.value other
]
[ Html.text deckInfo.name ]
in
Html.div [ HtmlA.class "primary" ]
[ Wl.select
[ HtmlA.id "built-in-selector"
, WlA.outlined
, Id >> Source.BuiltIn >> update |> HtmlE.onInput
]
(decks |> List.map deck)
]
Nothing ->
Html.nothing
details : Id -> Shared -> Source.Details
details (Id given) shared =
let
isSame deckInfo =
case deckInfo.id of
Id other ->
given == other
in
{ name =
shared.sources.builtIn
|> Maybe.andThen (.decks >> List.filter isSame >> List.head >> Maybe.map .name)
|> Maybe.withDefault ""
, url = Nothing
}
tooltip : Id -> Shared -> Maybe ( String, Html msg )
tooltip (Id given) shared =
( "builtin-" ++ given, Html.span [] [ details (Id given) shared |> .name |> Html.text ] ) |> Just
logo : () -> Maybe (Html msg)
logo () =
Nothing
@@ -0,0 +1,17 @@
module MassiveDecks.Card.Source.BuiltIn.Model exposing (Id(..))
{-| Models for the built-in source.
-}
{-| The id for a built-in deck.
-}
type Id
= Id String
{-| Create an id from a string.
-}
playCode : String -> Id
playCode string =
string |> Id
@@ -25,6 +25,7 @@ methods playCode =
{ name = name
, logo = logo
, empty = empty
, id = id
, problems = problems playCode
, defaultDetails = details playCode
, tooltip = tooltip playCode
@@ -38,6 +39,7 @@ generalMethods =
{ name = name
, logo = logo
, empty = empty
, id = id
}
@@ -45,13 +47,18 @@ generalMethods =
{- Private -}
id : () -> String
id () =
"Cardcast"
name : () -> MdString
name () =
Strings.Cardcast
empty : () -> Source.External
empty () =
empty : Shared -> Source.External
empty shared =
"" |> playCode |> Source.Cardcast
@@ -61,6 +68,9 @@ equals (PlayCode pc) source =
Source.Cardcast (PlayCode other) ->
pc == other
_ ->
False
problems : PlayCode -> () -> List (Message msg)
problems (PlayCode pc) () =
@@ -92,6 +102,9 @@ editor (PlayCode pc) shared existing update =
in
playCode |> Maybe.justIf (existing |> List.all notSameDeck)
_ ->
Nothing
recentDeck (PlayCode recent) =
Html.option [ HtmlA.value recent ] []
in
@@ -116,8 +129,8 @@ details (PlayCode pc) shared =
}
tooltip : PlayCode -> () -> Maybe ( String, Html msg )
tooltip (PlayCode pc) () =
tooltip : PlayCode -> Shared -> Maybe ( String, Html msg )
tooltip (PlayCode pc) _ =
( "cardcast-" ++ pc, Html.span [] [ logoInternal, Html.text pc ] ) |> Just
@@ -15,7 +15,7 @@ methods =
{ name = name shared
, url = Nothing
}
, tooltip = \() -> Nothing
, tooltip = \_ -> Nothing
}
@@ -13,5 +13,5 @@ methods =
{ name = ""
, url = Nothing
}
, tooltip = \() -> Nothing
, tooltip = \_ -> Nothing
}
@@ -74,7 +74,7 @@ type alias ExternalGeneralMethods msg =
-}
type alias IsSpecific general msg =
{ general
| tooltip : () -> Maybe ( String, Html msg )
| tooltip : Shared -> Maybe ( String, Html msg )
, defaultDetails : Shared -> Details
}
@@ -93,5 +93,6 @@ type alias IsSpecificExternal general msg =
-}
type alias IsGeneralExternal rest =
{ rest
| empty : () -> External
| empty : Shared -> External
, id : () -> String
}
@@ -1,11 +1,15 @@
module MassiveDecks.Card.Source.Model exposing
( Details
( BuiltInDeck
, BuiltInInfo
, Details
, External(..)
, Info
, LoadFailureReason(..)
, Source(..)
, Summary
)
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
@@ -31,7 +35,8 @@ sources are more limited and specific.
-}
type External
= Cardcast Cardcast.PlayCode
= BuiltIn BuiltIn.Id
| Cardcast Cardcast.PlayCode
{-| A summary of the contents of the source deck.
@@ -56,3 +61,19 @@ type alias Details =
type LoadFailureReason
= SourceFailure
| NotFound
{-| Information about what sources are available from the server.
-}
type alias Info =
{ builtIn : Maybe BuiltInInfo
, cardcast : Bool
}
type alias BuiltInInfo =
{ decks : List BuiltInDeck }
type alias BuiltInDeck =
{ name : String, id : BuiltIn.Id }
+2
View File
@@ -1,5 +1,6 @@
module MassiveDecks.Messages exposing (Msg(..))
import MassiveDecks.Card.Source.Model as Source
import MassiveDecks.Cast.Model as Cast
import MassiveDecks.Error.Messages as Error
import MassiveDecks.Notifications.Model as Notifications
@@ -27,5 +28,6 @@ type Msg
| UpdateToken Lobby.Auth
| CastStatusUpdate Cast.Status
| RemoteCommand Cast.RemoteControlCommand
| UpdateSources Source.Info
| Refresh
| BlockedExternalUrl
+2
View File
@@ -4,6 +4,7 @@ module MassiveDecks.Model exposing
)
import Browser.Navigation as Navigation
import MassiveDecks.Card.Source.Model as Sources
import MassiveDecks.Cast.Model as Cast
import MassiveDecks.Notifications.Model as Notifications
import MassiveDecks.Settings.Model as Settings exposing (Settings)
@@ -23,6 +24,7 @@ type alias Shared =
, speech : Speech.Model
, notifications : Notifications.Model
, remoteMode : Bool
, sources : Sources.Info
}
+69 -16
View File
@@ -16,6 +16,7 @@ module MassiveDecks.Models.Decoders exposing
, remoteControlCommand
, revealingRound
, settings
, sourceInfo
, tokenValidity
, userId
, userSummary
@@ -28,6 +29,7 @@ import Json.Patch
import MassiveDecks.Card.Model as Card exposing (Call, Response)
import MassiveDecks.Card.Parts as Parts exposing (Part, Parts)
import MassiveDecks.Card.Play as Play exposing (Play)
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
import MassiveDecks.Card.Source.Model as Source exposing (Source)
import MassiveDecks.Cast.Model as Cast
@@ -54,6 +56,26 @@ import MassiveDecks.User as User exposing (User)
import Set exposing (Set)
sourceInfo : Json.Decoder Source.Info
sourceInfo =
Json.succeed Source.Info
|> Json.optional "builtIn" (builtInInfo |> Json.map Just) Nothing
|> Json.optional "cardcast" Json.bool False
builtInInfo : Json.Decoder Source.BuiltInInfo
builtInInfo =
Json.succeed Source.BuiltInInfo
|> Json.required "decks" (Json.list builtInDeck)
builtInDeck : Json.Decoder Source.BuiltInDeck
builtInDeck =
Json.succeed Source.BuiltInDeck
|> Json.required "name" Json.string
|> Json.required "id" (Json.string |> Json.map BuiltIn.Id)
unknownValue : String -> String -> Json.Decoder a
unknownValue name value =
("Unknown " ++ name ++ ": \"" ++ value ++ "\".") |> Json.fail
@@ -182,6 +204,9 @@ externalSource =
externalSourceByName : String -> Json.Decoder Source.External
externalSourceByName name =
case name of
"BuiltIn" ->
Json.field "id" Json.string |> Json.map (BuiltIn.Id >> Source.BuiltIn)
"Cardcast" ->
Json.field "playCode" Json.string |> Json.map (Cardcast.playCode >> Source.Cardcast)
@@ -869,32 +894,60 @@ parts =
part : Json.Decoder Part
part =
Json.oneOf
[ Json.string |> Json.map Parts.Text
, transform |> Json.map Parts.Slot
[ Json.string |> Json.map (\t -> Parts.Text t Parts.NoStyle)
, styled
, slot
]
slot : Json.Decoder Parts.Part
slot =
Json.succeed Parts.Slot
|> Json.optional "transform" transform Parts.NoTransform
|> Json.optional "style" style Parts.NoStyle
styled : Json.Decoder Parts.Part
styled =
Json.succeed Parts.Text
|> Json.required "text" Json.string
|> Json.optional "style" style Parts.NoStyle
transform : Json.Decoder Parts.Transform
transform =
Json.maybe (Json.field "transform" Json.string) |> Json.andThen transformByName
Json.string |> Json.andThen transformByName
transformByName : Maybe String -> Json.Decoder Parts.Transform
transformByName maybeName =
case maybeName of
Nothing ->
Json.succeed Parts.Stay
transformByName : String -> Json.Decoder Parts.Transform
transformByName name =
case name of
"UpperCase" ->
Json.succeed Parts.UpperCase
Just name ->
case name of
"UpperCase" ->
Json.succeed Parts.UpperCase
"Capitalize" ->
Json.succeed Parts.Capitalize
"Capitalize" ->
Json.succeed Parts.Capitalize
_ ->
unknownValue "transform" name
_ ->
unknownValue "transform" name
style : Json.Decoder Parts.Style
style =
Json.string |> Json.andThen styleByName
styleByName : String -> Json.Decoder Parts.Style
styleByName name =
case name of
"Em" ->
Json.succeed Parts.Em
"Strong" ->
Json.succeed Parts.Strong
_ ->
unknownValue "style" name
round : Json.Decoder Round
@@ -23,6 +23,7 @@ module MassiveDecks.Models.Encoders exposing
import Dict
import Json.Encode as Json
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
import MassiveDecks.Card.Source.Model as Source exposing (Source)
import MassiveDecks.Cast.Model as Cast
@@ -326,6 +327,9 @@ source s =
Source.Cardcast (Cardcast.PlayCode playCode) ->
Json.object [ ( "source", "Cardcast" |> Json.string ), ( "playCode", playCode |> Json.string ) ]
Source.BuiltIn (BuiltIn.Id id) ->
Json.object [ ( "source", "BuiltIn" |> Json.string ), ( "id", id |> Json.string ) ]
language : Language -> Json.Value
language l =
+4 -4
View File
@@ -82,16 +82,16 @@ init shared r auth =
]
in
fallbackAuth
|> Maybe.map (initWithAuth r >> Route.Continue)
|> Maybe.map (initWithAuth shared r >> Route.Continue)
|> Maybe.withDefault (Route.Redirect (Route.Start { section = Start.Join (Just r.gameCode) }))
initWithAuth : Route -> Auth -> ( Model, Cmd msg )
initWithAuth r auth =
initWithAuth : Shared -> Route -> Auth -> ( Model, Cmd msg )
initWithAuth shared r auth =
( { route = r
, auth = auth
, lobby = Nothing
, configure = Configure.init
, configure = Configure.init shared
, notificationId = 0
, notifications = []
, inviteDialogOpen = False
@@ -56,11 +56,11 @@ import Weightless as Wl
import Weightless.Attributes as WlA
init : Model
init =
init : Shared -> Model
init shared =
{ localConfig = default
, tab = Decks
, decks = Decks.init
, decks = Decks.init shared
, privacy = Privacy.init
, timeLimits = TimeLimits.init
, rules = Rules.init
@@ -43,9 +43,9 @@ componentById id =
all
init : Model
init =
{ toAdd = Source.default }
init : Shared -> Model
init shared =
{ toAdd = Source.default shared }
default : Config
@@ -66,7 +66,7 @@ update shared msg model =
( settings, settingsCmd ) =
Settings.onAddDeck source shared.settings
in
( { model | toAdd = Source.emptyMatching source }
( { model | toAdd = Source.emptyMatching shared source }
, { shared | settings = settings }
, Cmd.batch [ Actions.configure (addDeck source), settingsCmd ]
)
@@ -226,7 +226,7 @@ submitDeckAction wrap existing deckToAdd =
let
potentialProblems =
if List.any (getSource >> Source.equals deckToAdd) existing then
[ Strings.DeckAlreadyAdded |> Message.error ]
[ Strings.DeckAlreadyAdded |> Message.info ]
else
Source.problems deckToAdd
@@ -308,7 +308,7 @@ name wrap shared canEdit index source loading maybeError details =
|> Maybe.justIf canEdit
( maybeId, tooltip ) =
source |> Source.Ex |> Source.tooltip |> Maybe.decompose
source |> Source.Ex |> Source.tooltip shared |> Maybe.decompose
attrs =
maybeId |> Maybe.map (\id -> [ HtmlA.id id ]) |> Maybe.withDefault []
+7 -2
View File
@@ -585,8 +585,13 @@ examplePick2 : Card.Call
examplePick2 =
Card.call
(Parts.unsafeFromList
[ [ Parts.Slot Parts.Stay, Parts.Text " + ", Parts.Slot Parts.Stay ]
, [ Parts.Text " = ", Parts.Slot Parts.Stay ]
[ [ Parts.Slot Parts.NoTransform Parts.NoStyle
, Parts.Text " + " Parts.NoStyle
, Parts.Slot Parts.NoTransform Parts.NoStyle
]
, [ Parts.Text " = " Parts.NoStyle
, Parts.Slot Parts.NoTransform Parts.NoStyle
]
]
)
""
@@ -5,4 +5,4 @@ import MassiveDecks.Requests.HttpData.Messages as HttpData
type Msg
= SummaryUpdate (HttpData.Msg () (List Summary))
= SummaryUpdate (HttpData.Msg Never (List Summary))
@@ -12,7 +12,7 @@ import MassiveDecks.Requests.HttpData.Model exposing (HttpData)
{-| The model for the lobby browser.
-}
type alias Model =
HttpData () (List Summary)
HttpData Never (List Summary)
{-| An external summary of a lobby.
@@ -9,7 +9,7 @@ import MassiveDecks.Requests.HttpData.Messages as HttpData
type Msg
= GameCodeChanged String
| NameChanged String
| StartGame (HttpData.Msg () Lobby.Auth)
| StartGame (HttpData.Msg Never Lobby.Auth)
| JoinGame (HttpData.Msg MdError Lobby.Auth)
| LobbyBrowserMsg LobbyBrowser.Msg
| PasswordChanged String
@@ -20,7 +20,7 @@ type alias Model =
, lobbies : LobbyBrowser.Model
, name : String
, gameCode : Maybe GameCode
, newLobbyRequest : HttpData () Lobby.Auth
, newLobbyRequest : HttpData Never Lobby.Auth
, joinLobbyRequest : HttpData MdError Lobby.Auth
, password : Maybe String
, overlay : Maybe MdString
+25 -5
View File
@@ -3,11 +3,13 @@ module MassiveDecks.Requests.Api exposing
, joinLobby
, lobbySummaries
, newLobby
, sourceInfo
)
import Dict exposing (Dict)
import Http
import Json.Decode as Json
import MassiveDecks.Card.Source.Model as Source
import MassiveDecks.Error.Model as Error
import MassiveDecks.Models.Decoders as Decoders
import MassiveDecks.Models.Encoders as Encoders
@@ -25,7 +27,7 @@ import Url.Builder
{-| List the public lobbies.
-}
lobbySummaries : (Request.Response () (List LobbyBrowser.Summary) -> msg) -> Request msg
lobbySummaries : (Request.Response Never (List LobbyBrowser.Summary) -> msg) -> Request msg
lobbySummaries msg =
{ method = "GET"
, headers = []
@@ -39,7 +41,7 @@ lobbySummaries msg =
{-| Create a new lobby.
-}
newLobby : (Request.Response () Lobby.Auth -> msg) -> Start.LobbyCreation -> Request msg
newLobby : (Request.Response Never Lobby.Auth -> msg) -> Start.LobbyCreation -> Request msg
newLobby msg creation =
{ method = "POST"
, headers = []
@@ -51,6 +53,8 @@ newLobby msg creation =
}
{-| Join a lobby.
-}
joinLobby : (Request.Response MdError Lobby.Auth -> msg) -> GameCode -> User.Registration -> Request msg
joinLobby msg gameCode registration =
{ method = "POST"
@@ -63,7 +67,9 @@ joinLobby msg gameCode registration =
}
checkAlive : (Request.Response () (Dict Lobby.Token Bool) -> msg) -> List Lobby.Token -> Request msg
{-| Check if previously joined lobbies are still going.
-}
checkAlive : (Request.Response Never (Dict Lobby.Token Bool) -> msg) -> List Lobby.Token -> Request msg
checkAlive msg tokens =
{ method = "POST"
, headers = []
@@ -75,6 +81,20 @@ checkAlive msg tokens =
}
{-| Find out what sources the server offers.
-}
sourceInfo : (Request.Response Never Source.Info -> msg) -> Request msg
sourceInfo msg =
{ method = "GET"
, headers = []
, url = url [ "sources" ]
, body = Http.emptyBody
, expect = Request.expectResponse msg noError Decoders.sourceInfo
, timeout = Nothing
, tracker = Nothing
}
{- Private -}
@@ -92,6 +112,6 @@ url path =
Url.Builder.absolute ([ "api" ] ++ path) []
noError : Json.Decoder ()
noError : Json.Decoder Never
noError =
Json.succeed ()
Json.fail "No specific errors are expected for this request."
+1
View File
@@ -204,6 +204,7 @@ type MdString
| Cardcast -- The name of the Cardcast service.
| CardcastPlayCode -- A term referring to the play code that identifies a deck on Cardcast.
| CardcastEmptyPlayCode -- A description of the problem of the entered Cardcast play code being empty.
| BuiltIn -- A term referring to decks of cards that are provided by this instance of the game.
| APlayer -- A short description of a generic player in the game in the context of being the author of a card.
| DeckAlreadyAdded -- A description of the problem of the deck already being added to the game configuration.
| ConfigureDecks -- A name for the section of the configuration screen for changing the decks for the game.
@@ -4,7 +4,7 @@ module MassiveDecks.Strings.Languages.En exposing (pack)
This is the primary language, strings here are the canonical representation, and are suitable to translate from.
-}
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
import MassiveDecks.Card.Source.Model as Source
import MassiveDecks.Strings exposing (MdString(..))
import MassiveDecks.Strings.Translation as Translation exposing (Result(..))
@@ -15,7 +15,7 @@ pack =
{ code = "en"
, name = English
, translate = translate
, recommended = "CAHBS" |> Cardcast.playCode |> Source.Cardcast
, recommended = "cah-base-en" |> BuiltIn.Id |> Source.BuiltIn
}
@@ -714,6 +714,9 @@ translate mdString =
CardcastEmptyPlayCode ->
[ Text "Enter a ", Ref CardcastPlayCode, Text " for the deck you want to add." ]
BuiltIn ->
[ Text "Built-in" ]
APlayer ->
[ Text "A Player" ]
@@ -1,8 +1,8 @@
module MassiveDecks.Strings.Languages.It exposing (pack)
{- General Italian translation -}
{- Italian translation -}
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
import MassiveDecks.Card.Source.Model as Source
import MassiveDecks.Strings exposing (MdString(..))
import MassiveDecks.Strings.Translation as Translation exposing (Result(..))
@@ -13,7 +13,7 @@ pack =
{ code = "it"
, name = Italian
, translate = translate
, recommended = "CAHBS" |> Cardcast.playCode |> Source.Cardcast
, recommended = "cah-base-en" |> BuiltIn.Id |> Source.BuiltIn
}
@@ -482,9 +482,11 @@ translate mdString =
[ Text (String.fromInt numberOfCards) ]
-- Lobby
-- TODO: Translate
LobbyNameLabel ->
[ Text "Game Name" ]
-- TODO: Translate
DefaultLobbyName { owner } ->
[ Text owner, Text "'s Game" ]
@@ -730,6 +732,10 @@ translate mdString =
CardcastEmptyPlayCode ->
[ Text "Inserisci il ", Ref CardcastPlayCode, Text " per il mazzo che vuoi aggiungere." ]
-- TODO: Translate
BuiltIn ->
[ Text "Built-in" ]
APlayer ->
[ Text "Un giocatore" ]
@@ -3,7 +3,7 @@ module MassiveDecks.Strings.Languages.PtBR exposing (pack)
{-| Brazilian Portuguese translation.
-}
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
import MassiveDecks.Card.Source.Model as Source
import MassiveDecks.Strings exposing (MdString(..))
import MassiveDecks.Strings.Translation as Translation exposing (Result(..))
@@ -14,7 +14,7 @@ pack =
{ code = "ptBR"
, name = BrazilianPortuguese
, translate = translate
, recommended = "CAHBS" |> Cardcast.playCode |> Source.Cardcast
, recommended = "cah-base-en" |> BuiltIn.Id |> Source.BuiltIn
}
@@ -482,9 +482,11 @@ translate mdString =
[ Text (String.fromInt numberOfCards) ]
-- Lobby
-- TODO: Translate
LobbyNameLabel ->
[ Text "Game Name" ]
-- TODO: Translate
DefaultLobbyName { owner } ->
[ Text owner, Text "'s Game" ]
@@ -730,6 +732,10 @@ translate mdString =
CardcastEmptyPlayCode ->
[ Text "Digite um ", Ref CardcastPlayCode, Text " para o deck que você queira adicionar." ]
-- TODO: Translate
BuiltIn ->
[ Text "Built-in" ]
APlayer ->
[ Text "Um jogador" ]
+2 -2
View File
@@ -38,7 +38,7 @@
align-content: flex-start;
justify-content: flex-start;
span {
span, em, strong {
white-space: pre-wrap;
overflow-wrap: break-word;
word-break: break-all;
@@ -47,7 +47,7 @@
.slot {
display: contents;
span {
span, em, strong {
text-decoration: underline;
}
@@ -124,6 +124,11 @@
--input-padding-top-bottom: 0.9em;
}
#built-in-selector {
height: 100%;
--input-padding-top-bottom: 0.9em;
}
.house-rules {
margin-top: 2em;
}