Add pokedex detail page.

This commit is contained in:
Dillon Kearns 2021-06-01 10:57:08 -07:00
parent d6e9bf3818
commit cc316d5cd7
3 changed files with 143 additions and 2 deletions

View File

@ -9,6 +9,7 @@ import OptimizedDecoder as Decode
import Page exposing (Page, PageWithState, StaticPayload) import Page exposing (Page, PageWithState, StaticPayload)
import Pages.PageUrl exposing (PageUrl) import Pages.PageUrl exposing (PageUrl)
import Pages.Url import Pages.Url
import Route
import Secrets import Secrets
import Shared import Shared
import View exposing (View) import View exposing (View)

View File

@ -0,0 +1,106 @@
module Page.PokedexNumber_ exposing (Data, Model, Msg, page)
import DataSource exposing (DataSource)
import DataSource.Http
import Head
import Head.Seo as Seo
import Html exposing (..)
import Html.Attributes exposing (src)
import OptimizedDecoder as Decode
import Page exposing (Page, PageWithState, StaticPayload)
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
import Secrets
import Shared
import View exposing (View)
type alias Model =
()
type alias Msg =
Never
type alias RouteParams =
{ pokedexnumber : String }
page : Page RouteParams Data
page =
Page.prerenderedRouteWithFallback
{ head = head
, routes = routes
, data = data
, handleFallback =
\{ pokedexnumber } ->
let
asNumber : Int
asNumber =
String.toInt pokedexnumber |> Maybe.withDefault -1
in
DataSource.succeed
(asNumber > 0 && asNumber < 150)
}
|> Page.buildNoState { view = view }
routes : DataSource (List RouteParams)
routes =
DataSource.succeed []
data : RouteParams -> DataSource Data
data routeParams =
DataSource.Http.get (Secrets.succeed ("https://pokeapi.co/api/v2/pokemon/" ++ routeParams.pokedexnumber))
(Decode.map2 Data
(Decode.field "forms" (Decode.index 0 (Decode.field "name" Decode.string)))
(Decode.field "types" (Decode.list (Decode.field "type" (Decode.field "name" Decode.string))))
)
head :
StaticPayload Data RouteParams
-> List Head.Tag
head static =
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = Pages.Url.external "TODO"
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
}
, description = "TODO"
, locale = Nothing
, title = "TODO title" -- metadata.title -- TODO
}
|> Seo.website
type alias Data =
{ name : String
, abilities : List String
}
view :
Maybe PageUrl
-> Shared.Model
-> StaticPayload Data RouteParams
-> View Msg
view maybeUrl sharedModel static =
{ title = static.data.name
, body =
[ h1 []
[ text static.data.name
]
, text (static.data.abilities |> String.join ", ")
, img
[ src <| "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/" ++ static.routeParams.pokedexnumber ++ ".png"
]
[]
]
}

View File

@ -1,7 +1,7 @@
module Page exposing module Page exposing
( Builder(..) ( Builder(..)
, StaticPayload , StaticPayload
, prerenderedRoute, singleRoute, serverlessRoute , prerenderedRoute, prerenderedRouteWithFallback, singleRoute, serverlessRoute
, Page, buildNoState , Page, buildNoState
, PageWithState, buildWithLocalState, buildWithSharedState , PageWithState, buildWithLocalState, buildWithSharedState
) )
@ -30,7 +30,7 @@ But before the user even requests the page, we have the following data:
- `sharedStatic` - we can access any shared data between pages. For example, you may have fetched the name of a blog ("Jane's Blog") from the API for a Content Management System (CMS). - `sharedStatic` - we can access any shared data between pages. For example, you may have fetched the name of a blog ("Jane's Blog") from the API for a Content Management System (CMS).
- `static` - this is the static data for this specific page. If you use `noData`, then this will be `()`, meaning there is no page-specific static data. - `static` - this is the static data for this specific page. If you use `noData`, then this will be `()`, meaning there is no page-specific static data.
@docs prerenderedRoute, singleRoute, serverlessRoute @docs prerenderedRoute, prerenderedRouteWithFallback, singleRoute, serverlessRoute
## Stateless Page Modules ## Stateless Page Modules
@ -237,6 +237,40 @@ prerenderedRoute { data, head, routes } =
} }
{-| -}
prerenderedRouteWithFallback :
{ data : routeParams -> DataSource data
, routes : DataSource (List routeParams)
, handleFallback : routeParams -> DataSource Bool
, head : StaticPayload data routeParams -> List Head.Tag
}
-> Builder routeParams data
prerenderedRouteWithFallback { data, head, routes, handleFallback } =
WithData
{ data = data
, staticRoutes = routes
, head = head
, serverless = False
, handleRoute =
\routeParams ->
handleFallback routeParams
|> DataSource.andThen
(\handleFallbackResult ->
if handleFallbackResult then
DataSource.succeed True
else
-- we want to lazily evaluate this in our on-demand builders
-- so we try handle fallback first and short-circuit in those cases
-- TODO - we could make an optimization to handle this differently
-- between on-demand builders and the dev server
-- we only need to match the pre-rendered routes in the dev server,
-- not in on-demand builders
routes |> DataSource.map (List.member routeParams)
)
}
{-| -} {-| -}
serverlessRoute : serverlessRoute :
{ data : (ServerRequest decodedRequest -> DataSource decodedRequest) -> routeParams -> DataSource data { data : (ServerRequest decodedRequest -> DataSource decodedRequest) -> routeParams -> DataSource data