diff --git a/www/src/Pages/Collection.elm b/www/src/Pages/Collection.elm index 7fcb243..9dbbfd1 100644 --- a/www/src/Pages/Collection.elm +++ b/www/src/Pages/Collection.elm @@ -350,111 +350,6 @@ searchBar model = viewCardBrowser : Model -> E.Element Msg viewCardBrowser model = let - viewCard : Card.Copy -> E.Element Msg - viewCard copy = - let - maxDimensions = - { width = 480, height = 680 } - in - E.el - [ Border.rounded 10 - , E.clip - , E.width (E.fill |> E.maximum maxDimensions.width) - ] - <| - E.image - [ E.width E.fill - , E.behindContent <| - E.html <| - Spinner.view UI.manaSpinner model.spinner - ] - { src = - Url.Builder.crossOrigin "https://api.scryfall.com" - [ "cards", copy.card.scryfallId ] - [ Url.Builder.string "format" "image" - , Url.Builder.string "version" "border_crop" - ] - , description = copy.card.name - } - - prices card = - Maybe.Extra.values - [ Maybe.map (\usd -> { currency = "usd", amount = usd }) <| - Maybe.Extra.or card.prices.usd card.prices.usd_foil - , Maybe.map (\eur -> { currency = "eur", amount = eur }) <| - Maybe.Extra.or card.prices.eur card.prices.eur_foil - , Maybe.map (\tix -> { currency = "tix", amount = tix }) card.prices.tix - ] - - cardDetails copy = - let - cardImage = - if UI.isMobile model.device then - E.none - - else - E.row [ E.width E.fill ] - [ E.el [ E.width <| E.fillPortion 1 ] E.none - , E.el [ E.width <| E.fillPortion 5 ] <| - viewCard copy - , E.el [ E.width <| E.fillPortion 1 ] E.none - ] - in - E.column - [ E.spacing 20 - , E.padding 10 - , E.width E.fill - ] - [ cardImage - , E.paragraph [ Font.heavy, Font.size 24, Font.center, Font.color UI.colors.title ] - [ E.text copy.card.name ] - , E.row [ E.spacing 5, E.centerX ] <| - List.map UI.priceBadge (prices copy.card) - , E.wrappedRow [ E.spacing 10 ] [ Symbol.text model.symbols 24 copy.card.manaCost, UI.text copy.card.typeLine ] - , E.paragraph [] <| - List.map (Symbol.text model.symbols 16) (String.lines copy.card.oracleText) - ] - - details = - if UI.isMobile model.device then - E.el - [ E.spacing 10 - , E.padding 10 - , E.height E.fill - , E.width E.fill - , Background.color UI.colors.sidebar - , E.scrollbarY - ] - (model.activeCard - |> Maybe.map cardDetails - |> Maybe.withDefault E.none - ) - - else - E.el - [ E.alignTop - , E.width <| E.fillPortion 1 - , E.height E.fill - , E.scrollbarY - , Background.color UI.colors.sidebar - ] - (model.activeCard - |> Maybe.map cardDetails - |> Maybe.withDefault - E.none - ) - - closedetails = - Input.button - [ E.height (E.px 30) - , E.width E.fill - , Background.color UI.colors.secondary - , Border.rounded 5 - , Font.color UI.colors.text - , Font.center - ] - { label = E.text "Close", onPress = Just ClearCardDetails } - navButton text maybeUrl = case maybeUrl of Just url -> @@ -535,29 +430,7 @@ viewCardBrowser model = Spinner.view UI.manaSpinner model.spinner Ready cardPage -> - if UI.isMobile model.device then - E.column - [ E.width E.fill - , E.height E.fill - , Font.color UI.colors.text - , E.scrollbarY - ] - <| - case model.activeCard of - Just _ -> - [ details, closedetails ] - - Nothing -> - [ cards cardPage ] - - else - E.row - [ E.width E.fill - , E.height E.fill - , Font.color UI.colors.text - , E.scrollbarY - ] - [ details, cards cardPage ] + cards cardPage onEnter : msg -> E.Attribute msg @@ -577,31 +450,144 @@ onEnter msg = ) +viewCardDetails model = + let + viewCard : Card.Copy -> E.Element Msg + viewCard copy = + let + maxDimensions = + { width = 480, height = 680 } + in + E.el + [ Border.rounded 10 + , E.clip + , E.width (E.fill |> E.maximum maxDimensions.width) + ] + <| + E.image + [ E.width E.fill + , E.behindContent <| + E.html <| + Spinner.view UI.manaSpinner model.spinner + ] + { src = + Url.Builder.crossOrigin "https://api.scryfall.com" + [ "cards", copy.card.scryfallId ] + [ Url.Builder.string "format" "image" + , Url.Builder.string "version" "border_crop" + ] + , description = copy.card.name + } + + prices card = + Maybe.Extra.values + [ Maybe.map (\usd -> { currency = "usd", amount = usd }) <| + Maybe.Extra.or card.prices.usd card.prices.usd_foil + , Maybe.map (\eur -> { currency = "eur", amount = eur }) <| + Maybe.Extra.or card.prices.eur card.prices.eur_foil + , Maybe.map (\tix -> { currency = "tix", amount = tix }) card.prices.tix + ] + + cardDetails copy = + let + cardImage = + if UI.isMobile model.device then + E.none + + else + E.row [ E.width E.fill ] + [ E.el [ E.width <| E.fillPortion 1 ] E.none + , E.el [ E.width <| E.fillPortion 5 ] <| + viewCard copy + , E.el [ E.width <| E.fillPortion 1 ] E.none + ] + in + E.column + [ E.spacing 20 + , E.padding 10 + , E.width E.fill + , E.height E.fill + , Font.color UI.colors.text + ] + [ cardImage + , E.paragraph [ Font.heavy, Font.size 24, Font.center, Font.color UI.colors.title ] + [ E.text copy.card.name ] + , E.row [ E.spacing 5, E.centerX ] <| + List.map UI.priceBadge (prices copy.card) + , E.wrappedRow [ E.spacing 10 ] [ Symbol.text model.symbols 24 copy.card.manaCost, UI.text copy.card.typeLine ] + , E.paragraph [] <| + List.map (Symbol.text model.symbols 16) (String.lines copy.card.oracleText) + ] + + closedetails = + Input.button + [ E.height (E.px 30) + , E.width E.fill + , Background.color UI.colors.secondary + , Border.rounded 5 + , Font.color UI.colors.text + , Font.center + ] + { label = E.text "Close", onPress = Just ClearCardDetails } + in + if UI.isMobile model.device then + E.column + [ E.width E.fill + , E.height E.fill + ] + [ model.activeCard + |> Maybe.map cardDetails + |> Maybe.withDefault E.none + , closedetails + ] + + else + E.el + [ E.alignTop + , E.width <| E.fillPortion 1 + , E.height E.fill + , E.scrollbarY + , Background.color UI.colors.sidebar + ] + (model.activeCard + |> Maybe.map cardDetails + |> Maybe.withDefault + E.none + ) + + view : Model -> E.Element Msg view model = - E.column - [ E.width E.fill - , E.height E.fill - ] - [ searchBar model - , viewCardBrowser model - , UI.footer <| + let + footer = case model.collectionStatistics of Just statistics -> - E.el [ E.centerY, Font.size 16, Font.italic ] <| - E.text <| - String.concat - [ String.fromInt statistics.cards - , " cards in collection spanning " - , String.fromInt statistics.sets - , " sets (Estimated value: $" - , statistics.value - , ")" - ] + Just <| + E.el [ E.centerY, Font.size 16, Font.italic ] <| + E.text <| + String.concat + [ String.fromInt statistics.cards + , " cards in collection spanning " + , String.fromInt statistics.sets + , " sets (Estimated value: $" + , statistics.value + , ")" + ] Nothing -> - E.none - ] + Nothing + in + UI.layout model.device + { toolbar = Just <| searchBar model + , sidebar = + if UI.isMobile model.device then + Maybe.map (\_ -> viewCardDetails model) model.activeCard + + else + Just <| viewCardDetails model + , content = viewCardBrowser model + , footer = footer + } subscriptions : Model -> Sub Msg diff --git a/www/src/Pages/DeckEditor.elm b/www/src/Pages/DeckEditor.elm index 7a88011..b86a469 100644 --- a/www/src/Pages/DeckEditor.elm +++ b/www/src/Pages/DeckEditor.elm @@ -170,38 +170,43 @@ viewDeck symbols deck = view : Model -> E.Element Msg view model = - E.column - [ E.width E.fill - , E.height E.fill - , E.clipX - ] - [ case model.deck of - Ready deck -> - viewDeck model.symbols deck - - Failed -> - E.none - - NotFound -> - UI.pageNotFound - - Loading -> - E.el [ E.height E.fill, E.centerX ] <| - E.html <| - Spinner.view UI.manaSpinner - model.spinner - , UI.footer <| + let + footer = case model.deck of Ready deck -> - UI.text <| - String.join " " - [ String.fromInt (List.sum <| List.map .quantity deck.cards) - , "cards" - ] + Just <| + UI.text <| + String.join " " + [ String.fromInt (List.sum <| List.map .quantity deck.cards) + , "cards" + ] _ -> + Nothing + + content = + case model.deck of + Ready deck -> + viewDeck model.symbols deck + + Failed -> E.none - ] + + NotFound -> + UI.pageNotFound + + Loading -> + E.el [ E.height E.fill, E.centerX ] <| + E.html <| + Spinner.view UI.manaSpinner + model.spinner + in + UI.layout model.device + { toolbar = Nothing + , sidebar = Nothing + , content = content + , footer = footer + } subscriptions : Model -> Sub Msg diff --git a/www/src/Pages/DeckList.elm b/www/src/Pages/DeckList.elm index 0af25cc..d633045 100644 --- a/www/src/Pages/DeckList.elm +++ b/www/src/Pages/DeckList.elm @@ -103,7 +103,13 @@ view model = ] [ UI.title deck.name ] in - E.column [ E.width E.fill, E.centerX ] <| List.map deckRow deckPage.values + UI.layout model.device + { toolbar = Nothing + , sidebar = Nothing + , content = + E.column [ E.width E.fill, E.centerX ] <| List.map deckRow deckPage.values + , footer = Nothing + } subscriptions : Model -> Sub Msg diff --git a/www/src/UI.elm b/www/src/UI.elm index aae216e..6e44090 100644 --- a/www/src/UI.elm +++ b/www/src/UI.elm @@ -5,6 +5,7 @@ module UI exposing , footer , getViewport , isMobile + , layout , manaSpinner , pageNotFound , priceBadge @@ -325,3 +326,79 @@ footer element = , E.alignBottom ] element + + +type alias Page msg = + { toolbar : Maybe (E.Element msg) + , sidebar : Maybe (E.Element msg) + , content : E.Element msg + , footer : Maybe (E.Element msg) + } + + +layout : E.Device -> Page msg -> E.Element msg +layout device page = + let + toolbar : E.Element msg -> E.Element msg + toolbar element = + E.el + [ E.padding 10 + , E.spacing 10 + , E.width E.fill + , Background.color colors.navBar + ] + element + + sidebar : E.Element msg -> E.Element msg + sidebar element = + if isMobile device then + E.el + [ E.height E.fill + , E.width E.fill + , E.scrollbarY + , Background.color colors.sidebar + ] + element + + else + E.el + [ E.alignTop + , E.width <| E.fillPortion 1 + , E.height E.fill + , E.scrollbarY + , Background.color colors.sidebar + ] + element + + content : E.Element msg -> E.Element msg + content element = + E.el + [ E.width <| E.fillPortion 3 + , E.height E.fill + ] + element + + maybe : Maybe (E.Element msg) -> E.Element msg + maybe element = + Maybe.withDefault E.none element + in + E.column + [ E.width E.fill + , E.height E.fill + ] + [ maybe <| Maybe.map toolbar page.toolbar + , if isMobile device then + Maybe.withDefault page.content page.sidebar + + else + E.row + [ E.width E.fill + , E.height E.fill + , Font.color colors.text + , E.scrollbarY + ] + [ maybe <| Maybe.map sidebar page.sidebar + , content page.content + ] + , footer <| maybe page.footer + ]