| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- module Main exposing (..)
- import Browser exposing (Document)
- import Card exposing (CardData)
- import Database
- import Draft exposing (Draft)
- import Html exposing (Html, button, div, img, span, text)
- import Html.Attributes exposing (alt, class, classList, disabled, src)
- import Html.Events as Events exposing (onClick)
- import Html.Keyed as Keyed
- import Round
- import Zipper
- main =
- Browser.document
- { init = init
- , update = update
- , view = view
- , subscriptions = \_ -> Sub.none
- }
- type Model
- = Ready ReadyModel
- | Error ErrorModel
- type FocusStat
- = FocusALSA
- | FocusALPA
- | FocusGIHWR
- | FocusPickRate
- type alias ReadyModel =
- { draft : Draft
- , database : Database.Database
- , highlighted : Maybe Draft.PickCard
- , flipHighlighted : Bool
- , focusStat : FocusStat
- }
- type alias ErrorModel =
- { error : String
- }
- init : { setData : String, draftData : String } -> ( Model, Cmd Msg )
- init flags =
- case ( Draft.decode flags.draftData, Database.decode flags.setData flags.draftData ) of
- ( Ok draftData, Ok database ) ->
- ( Ready
- { draft = draftData
- , database = database
- , highlighted = Nothing
- , flipHighlighted = False
- , focusStat = FocusPickRate
- }
- , Cmd.none
- )
- ( Err err, Ok _ ) ->
- ( Error { error = "Error decoding draft data: " ++ err }, Cmd.none )
- ( Ok _, Err err ) ->
- ( Error { error = "Error decoding set data: " ++ err }, Cmd.none )
- ( Err draftError, Err databaseError ) ->
- ( Error { error = "Error decoding draft data: " ++ draftError ++ ", set data: " ++ databaseError }, Cmd.none )
- type Msg
- = Increment
- | Decrement
- | Highlight Draft.PickCard
- | FlipHighlightedCard
- | SetFocusStat FocusStat
- update : Msg -> Model -> ( Model, Cmd Msg )
- update msg model =
- case model of
- Ready mdl ->
- case msg of
- Increment ->
- ( Ready { mdl | draft = Zipper.moveRight mdl.draft }, Cmd.none )
- Decrement ->
- ( Ready { mdl | draft = Zipper.moveLeft mdl.draft }, Cmd.none )
- Highlight card ->
- ( Ready
- { mdl
- | highlighted = Just card
- , flipHighlighted = False
- }
- , Cmd.none
- )
- FlipHighlightedCard ->
- ( Ready { mdl | flipHighlighted = not mdl.flipHighlighted }, Cmd.none )
- SetFocusStat stat ->
- ( Ready { mdl | focusStat = stat }, Cmd.none )
- Error mdl ->
- ( Error mdl, Cmd.none )
- view : Model -> Document Msg
- view model =
- { title = "Drafter"
- , body =
- [ case model of
- Ready mdl ->
- viewReady mdl
- Error mdl ->
- viewError mdl
- ]
- }
- viewReady : ReadyModel -> Html Msg
- viewReady model =
- div [ class "grid grid-cols-12 gap-6 h-full bg-slate-100" ]
- [ viewSidebar model
- , viewDraft model
- , viewHighlightedCard model
- ]
- viewSidebar : ReadyModel -> Html Msg
- viewSidebar model =
- div [ class "col-span-2 p-6 bg-slate-600" ]
- [ button
- [ onClick Decrement
- , disabled (not (Zipper.hasLeft model.draft))
- , class "bg-slate-900 rounded text-white p-2 shadow disabled:opacity-50"
- ]
- [ text "Previous" ]
- , span [ class "text-white px-3 font-medium" ] [ text ("Pick " ++ String.fromInt (Zipper.position model.draft)) ]
- , button
- [ onClick Increment
- , class "bg-slate-900 rounded text-white p-2 shadow disabled:opacity-50"
- , disabled (not (Zipper.hasRight model.draft))
- ]
- [ text "Next" ]
- ]
- viewError : ErrorModel -> Html Msg
- viewError model =
- div [ class "error" ]
- [ text model.error ]
- viewDraft : ReadyModel -> Html Msg
- viewDraft model =
- let
- chosen =
- (Zipper.focus model.draft).chosen
- picks =
- List.map (\c -> viewKeyedCard model (chosen.name == c.name) c)
- (Zipper.focus model.draft).available
- viewFocusStatButton s =
- button
- [ onClick (SetFocusStat s)
- , classList [ ( "bg-slate-900 rounded text-white p-2 shadow mr-2 mb-2", True ), ( "bg-slate-500 shadow-inset", model.focusStat == s ) ]
- ]
- [ text <|
- case s of
- FocusPickRate ->
- "Pick rate"
- FocusALPA ->
- "ALPA"
- FocusGIHWR ->
- "GIHWR"
- FocusALSA ->
- "ALSA"
- ]
- in
- -- Making this a keyed node forces Elm to recreate each card when the card name changes,
- -- so the old image doesn't hang around during loading of the new card image
- div [ class "flex flex-col space-between col-span-8 " ]
- [ Keyed.node "div"
- [ class "flex-grow grid grid-cols-8 auto-rows-min gap-6 p-6" ]
- picks
- , div []
- [ viewFocusStatButton FocusPickRate
- , viewFocusStatButton FocusALPA
- , viewFocusStatButton FocusGIHWR
- , viewFocusStatButton FocusALSA
- ]
- ]
- viewHighlightedCard : ReadyModel -> Html Msg
- viewHighlightedCard model =
- div [ class "col-span-2 shadow-xl bg-slate-600 p-6" ]
- [ case model.highlighted of
- Just highlighted ->
- let
- url =
- case ( model.flipHighlighted, highlighted.backImage ) of
- ( True, Just backUrl ) ->
- backUrl
- _ ->
- highlighted.frontImage
- in
- div
- []
- [ img
- [ src url
- , alt highlighted.name
- , onClick FlipHighlightedCard
- ]
- []
- , viewCardDetailedPerformance model.database highlighted
- ]
- Nothing ->
- div [] []
- ]
- formatPercentage : Float -> String
- formatPercentage value =
- Round.round 2 (value * 100) ++ "%"
- viewCardDetailedPerformance : Database.Database -> Draft.PickCard -> Html Msg
- viewCardDetailedPerformance db { name } =
- let
- makeCardFacts : CardData -> List ( String, String )
- makeCardFacts cardData =
- [ ( "Pick rate"
- , Just <|
- formatPercentage (Card.pickRate cardData)
- )
- , ( "GIHWR"
- , Maybe.map formatPercentage (Card.gihwr cardData)
- )
- , ( "ALPA"
- , Maybe.map (Round.round 2) (Card.alpa cardData)
- )
- , ( "ALSA"
- , Maybe.map (Round.round 2) (Card.alsa cardData)
- )
- ]
- |> List.filterMap (\( label, value ) -> Maybe.map (\v -> ( label, v )) value)
- viewFact : ( String, String ) -> Html Msg
- viewFact ( label, value ) =
- div
- [ class "" ]
- [ div [] [ text label ]
- , div [] [ text value ]
- ]
- in
- case Database.get name db of
- Just cardData ->
- div
- [ class "" ]
- (List.map viewFact (makeCardFacts cardData))
- Nothing ->
- div [] [ text "Could not find card in database" ]
- viewKeyedCard : ReadyModel -> Bool -> Draft.PickCard -> ( String, Html Msg )
- viewKeyedCard model wasChosen { name, frontImage, backImage } =
- let
- stats =
- Database.get name model.database
- focusStat =
- case model.focusStat of
- FocusALSA ->
- Maybe.map (Round.round 2) (Maybe.andThen Card.alsa stats)
- FocusALPA ->
- Maybe.map (Round.round 2) (Maybe.andThen Card.alpa stats)
- FocusGIHWR ->
- Maybe.map formatPercentage (Maybe.andThen Card.gihwr stats)
- FocusPickRate ->
- Maybe.map (formatPercentage << Card.pickRate) stats
- in
- ( name
- , div
- [ classList
- [ ( "relative", True )
- , ( "border-4 border-green-500", wasChosen )
- ]
- , Events.onMouseEnter (Highlight { name = name, frontImage = frontImage, backImage = backImage })
- ]
- [ img [ src frontImage, alt name ] []
- , span [ class "absolute top-0 left-0 bg-green-100" ] [ text <| Maybe.withDefault "?" focusStat ]
- ]
- )
|