Skip to content

Instantly share code, notes, and snippets.

@TheSeamau5
Last active March 10, 2016 15:12
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save TheSeamau5/98527f7278a2c6f06092 to your computer and use it in GitHub Desktop.
Save TheSeamau5/98527f7278a2c6f06092 to your computer and use it in GitHub Desktop.
Artist Search Example
--------------------------
-- CORE LIBRARY IMPORTS --
--------------------------
import Json.Decode as Decode exposing (Decoder, object2, map, string, list, (:=))
import Task exposing (Task, andThen, succeed, fail, onError)
import Signal exposing (Signal, Mailbox, mailbox, message, send)
import String
-------------------------
-- THIRD PARTY IMPORTS --
-------------------------
import Html exposing (Html, text, div, input, img, a)
import Html.Attributes exposing (style, href, src, placeholder)
import Html.Events exposing (on, targetValue)
import Html.Lazy exposing (lazy, lazy2, lazy3)
import Http exposing (url, get)
import Markdown exposing (toHtml)
andMap = object2 (<|)
last : List a -> Maybe a
last list = case list of
[] -> Nothing
x :: [] -> Just x
x :: xs -> last xs
-----------------------------
-- LAST.FM URL AND API KEY --
-----------------------------
baseUrl =
"http://ws.audioscrobbler.com/2.0/"
apiKey =
"4cf3c87329172d056c2d67ee0617f5da"
-----------
-- MODEL --
-----------
type alias Model =
{ artist : Maybe Artist }
initialModel : Model
initialModel =
{ artist = Nothing }
type alias Artist =
{ name : String
, url : String
, bio : String
, imageSource : String
}
------------------
-- JSON PARSING --
------------------
type alias ArtistQueryJson =
{ artist : ArtistJson }
artistQueryJson : Decoder ArtistQueryJson
artistQueryJson = ArtistQueryJson
`map` ("artist" := artistJson)
type alias ArtistJson =
{ name : String
, url : String
, image : List ImageJson
, bio : BioJson
}
artistJson : Decoder ArtistJson
artistJson = ArtistJson
`map` ("name" := string)
`andMap` ("url" := string)
`andMap` ("image" := list imageJson)
`andMap` ("bio" := bioJson)
type alias ImageJson =
{ text : String
, size : String
}
imageJson : Decoder ImageJson
imageJson = ImageJson
`map` ("#text" := string)
`andMap` ("size" := string)
type alias BioJson =
{ summary : String }
bioJson : Decoder BioJson
bioJson = BioJson
`map` ("summary" := string)
-----------------
-- CONVERSIONS --
-----------------
jsonToArtist : ArtistQueryJson -> Artist
jsonToArtist {artist} =
let imageSrc = case last artist.image of
Nothing -> ""
Just image -> image.text
in
Artist (artist.name) (artist.url) (artist.bio.summary) (imageSrc)
-----------
-- TASKS --
-----------
getArtistInfo : String -> Task Http.Error ()
getArtistInfo artist =
let
requestUrl = url baseUrl
[ ("method", "artist.getInfo")
, ("artist", artist)
, ("api_key", apiKey)
, ("format", "json")
]
in get artistQueryJson requestUrl
`andThen` (jsonToArtist >> succeed)
`andThen` (Just >> send artistMailbox.address)
`onError` \_ -> send artistMailbox.address Nothing
---------------
-- MAILBOXES --
---------------
artistMailbox : Mailbox (Maybe Artist)
artistMailbox = mailbox Nothing
getArtistTaskMailbox : Mailbox (Task Http.Error ())
getArtistTaskMailbox = mailbox (succeed ())
-----------
-- PORTS --
-----------
port getArtistPort : Signal (Task Http.Error ())
port getArtistPort =
getArtistTaskMailbox.signal
-------------
-- SIGNALS --
-------------
model : Signal Model
model =
Signal.map Model artistMailbox.signal
----------
-- VIEW --
----------
type alias Style = List (String, String)
(:::) = (,)
artistInputStyle : Style
artistInputStyle =
[ "height" ::: "44px"
, "font-size" ::: "14pt"
, "font-weight" ::: "100"
, "width" ::: "90%"
, "max-width" ::: "400px"
, "max-height" ::: "44px"
, "align-self" ::: "center"
, "transition" ::: "all 0.2s ease-out"
]
artistInputWrapperStyle : Style
artistInputWrapperStyle =
[ "flex" ::: "2"
, "display" ::: "flex"
, "align-items" ::: "center"
, "justify-content" ::: "center"
, "transition" ::: "all 0.2s ease-out"
]
artistInput : Html
artistInput =
div
[ style artistInputWrapperStyle ]
[ input
[ style artistInputStyle
, placeholder "Search for Artist or Band"
, on "input" targetValue (getArtistInfo >> message getArtistTaskMailbox.address)
]
[]
]
artistViewWrapperStyle : Style
artistViewWrapperStyle =
[ "display" ::: "flex"
, "flex" ::: "6"
, "flex-direction" ::: "column"
, "width" ::: "100%"
, "justify-content" ::: "flex-start"
, "align-items" ::: "center"
, "transition" ::: "all 0.2s ease-out"
]
artistViewStyle : Style
artistViewStyle =
[ "display" ::: "flex"
, "flex-direction" ::: "row"
, "justify-content" ::: "space-between"
, "width" ::: "90%"
, "flex" ::: "1"
, "max-height" ::: "500px"
, "transition" ::: "all 0.2s ease-out"
]
emptyArtistViewStyle : Style
emptyArtistViewStyle =
[ "display" ::: "flex"
, "flex" ::: "0.0001"
, "transition" ::: "all 0.2s ease-out"
]
artistView : Model -> Html
artistView {artist} = case artist of
Nothing ->
div
[ style emptyArtistViewStyle ] []
Just artist ->
div
[ style artistViewWrapperStyle ]
[ div
[ style artistViewStyle ]
[ lazy3 leftView artist.name artist.url artist.bio
, lazy rightView artist.imageSource
]
]
rightViewStyle : String -> Style
rightViewStyle imageSource =
let
backgroundStyle = "url(" ++ imageSource ++ ") center center no-repeat"
in
[ "flex" ::: "1"
, "background" ::: backgroundStyle
, "background-size" ::: "cover"
, "transition" ::: "all 0.2s ease-out"
]
rightView : String -> Html
rightView imageSource =
div
[ style (rightViewStyle imageSource)
]
[]
leftViewStyle : Style
leftViewStyle =
[ "flex" ::: "1"
, "display" ::: "flex"
, "flex-direction" ::: "column"
, "transition" ::: "all 0.2s ease-out"
]
leftView : String -> String -> String -> Html
leftView name url bio =
div
[ style leftViewStyle ]
[ lazy2 artistTitle name url
, lazy artistBio bio
]
artistTitleStyle : Style
artistTitleStyle =
[ "font-size" ::: "52pt"
, "margin-left" ::: "5px"
, "margin-top" ::: "10px"
, "color" ::: "black"
, "font-weight" ::: "100"
, "transition" ::: "all 0.2s ease-out"
]
artistTitle : String -> String -> Html
artistTitle name url =
a
[ href url
, style artistTitleStyle
]
[ lazy text name ]
artistBioStyle : Style
artistBioStyle =
[ "font-size" ::: "16pt"
, "font-family" ::: "serif"
, "margin-left" ::: "5px"
, "margin-right" ::: "5px"
, "transition" ::: "all 0.2s ease-out"
]
artistBioWrapperStyle : Style
artistBioWrapperStyle =
[ "flex" ::: "6"
, "display" ::: "flex"
, "overflow" ::: "hidden"
, "align-items" ::: "flex-start"
, "justify-content" ::: "center"
, "transition" ::: "all 0.2s ease-out"
]
artistBio : String -> Html
artistBio bio =
div
[ style artistBioWrapperStyle ]
[ div
[ style artistBioStyle ]
[ text bio ]
]
mainViewStyle : Style
mainViewStyle =
[ "width" ::: "100vw"
, "height" ::: "100vh"
, "display" ::: "flex"
, "flex-direction" ::: "column"
, "font-weight" ::: "100"
, "transition" ::: "all 0.2s ease-out"
]
view : Model -> Html
view model =
div
[ style mainViewStyle ]
[ artistInput
, lazy artistView model
]
----------
-- MAIN --
----------
main : Signal Html
main = Signal.map view model
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment