Refactor page layout

This commit is contained in:
Correl Roush 2023-01-16 16:09:04 -05:00
parent df9d5e888f
commit b9511ff229
4 changed files with 249 additions and 175 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
]