Skip to content

Instantly share code, notes, and snippets.

@lambder
Forked from pdamoc/Counter.elm
Created May 18, 2016 16:34
Show Gist options
  • Save lambder/04794d46d14b4e2a2e37d3730adc45c2 to your computer and use it in GitHub Desktop.
Save lambder/04794d46d14b4e2a2e37d3730adc45c2 to your computer and use it in GitHub Desktop.
Widget Union
module Counter exposing (..)
import Html exposing (..)
import Html.Attributes exposing (style)
import Html.Events exposing (onClick)
-- MODEL
type alias Model = Int
init : Int -> Model
init v = v
-- UPDATE
type Msg = Increment | Decrement
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
model + 1
Decrement ->
model - 1
-- VIEW
view : Model -> Html Msg
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [ countStyle ] [ text (toString model) ]
, button [ onClick Increment ] [ text "+" ]
]
countStyle : Attribute Msg
countStyle =
style
[ ("font-size", "20px")
, ("font-family", "monospace")
, ("display", "inline-block")
, ("width", "50px")
, ("text-align", "center")
]
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "4.0.0 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.17.0 <= v < 0.18.0"
}
import Html.App as Html
import WidgetList exposing (init, update, view)
main : Program Never
main =
Html.program
{ init = init, update = update, view = view, subscriptions = \_ -> Sub.none }
module RandomGif exposing (..)
import Html exposing (..)
import Html.Attributes exposing (style)
import Html.Events exposing (onClick)
import Http
import Json.Decode as Json
import Task
-- MODEL
type alias Model =
{ topic : String
, gifUrl : String
}
init : String -> (Model, Cmd Msg)
init topic =
( Model topic "waiting.gif"
, getRandomGif topic
)
-- UPDATE
type Msg
= MorePlease
| FetchSucceed String
| FetchFail
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
MorePlease ->
(model, getRandomGif model.topic)
FetchSucceed newUrl ->
(Model model.topic newUrl, Cmd.none)
FetchFail ->
(model, Cmd.none)
-- VIEW
(=>) = (,)
view : Model -> Html Msg
view model =
div [ style [ "width" => "200px" ] ]
[ h2 [headerStyle] [text model.topic]
, div [imgStyle model.gifUrl] []
, button [ onClick MorePlease ] [ text "More Please!" ]
]
headerStyle : Attribute Msg
headerStyle =
style
[ "width" => "200px"
, "text-align" => "center"
]
imgStyle : String -> Attribute Msg
imgStyle url =
style
[ "display" => "inline-block"
, "width" => "200px"
, "height" => "200px"
, "background-position" => "center center"
, "background-size" => "cover"
, "background-image" => ("url('" ++ url ++ "')")
]
-- EFFECTS
getRandomGif : String -> Cmd Msg
getRandomGif topic =
let
url =
"http://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=" ++ topic
in
Http.get decodeGifUrl url
|> Task.perform (\_ -> FetchFail) FetchSucceed
decodeGifUrl : Json.Decoder String
decodeGifUrl =
Json.at ["data", "image_url"] Json.string
module Widget exposing (..)
import RandomGif
import Counter
import Html.App as App
import Html exposing (..)
type WidgetType = CounterType | RandomGifType
type Model = AGif RandomGif.Model | ACounter Counter.Model
initGif topic =
let
(gifMdl, cmd) = RandomGif.init topic
in
AGif gifMdl ! [Cmd.map AGifMsg cmd]
initCounter value =
ACounter (Counter.init value) ! []
type Msg = AGifMsg RandomGif.Msg | ACounterMsg Counter.Msg
update msg model =
case (msg, model) of
(AGifMsg m, AGif mdl) ->
let
(newMdl, cmd) = RandomGif.update m mdl
in
AGif newMdl ! [ Cmd.map AGifMsg cmd ]
(ACounterMsg m, ACounter mdl) ->
let
newMdl = Counter.update m mdl
in
ACounter newMdl ! []
_ -> model ! []
view : Model -> Html Msg
view model =
case model of
AGif mdl ->
div [] [App.map AGifMsg (RandomGif.view mdl)]
ACounter mdl ->
div [] [App.map ACounterMsg (Counter.view mdl)]
module WidgetList exposing (..)
import Html.App as H
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Json.Decode as Json
import Widget
-- MODEL
type alias Model =
{ topic : String
, gifList : List (Int, Widget.Model)
, uid : Int
}
init : (Model, Cmd Msg)
init =
( Model "" [] 0
, Cmd.none
)
-- UPDATE
type Msg
= Topic String
| Create Widget.WidgetType
| SubMsg Int Widget.Msg
update : Msg -> Model -> (Model, Cmd Msg)
update message model =
case (Debug.log "msg" message) of
Topic topic ->
( { model | topic = topic }
, Cmd.none
)
Create widgetType ->
let
(newWidget, fx) =
case widgetType of
Widget.RandomGifType ->
Widget.initGif model.topic
Widget.CounterType ->
Widget.initCounter 0
newModel =
Model "" (model.gifList ++ [(model.uid, newWidget)]) (model.uid + 1)
in
newModel ! [ Cmd.map (SubMsg model.uid) fx ]
SubMsg msgId msg ->
let
subUpdate ((id, widget) as entry) =
if id == msgId then
let
(newWidget, fx) = Widget.update msg widget
in
( (id, newWidget)
, Cmd.map (SubMsg id) fx
)
else
(entry, Cmd.none)
(newGifList, fxList) =
model.gifList
|> List.map subUpdate
|> List.unzip
in
{ model | gifList = newGifList } ! fxList
-- VIEW
(=>) = (,)
view : Model -> Html Msg
view model =
div []
[ input
[ placeholder "What kind of gifs do you want?"
, value model.topic
, onEnter model.topic
, on "input" (Json.map Topic targetValue)
, inputStyle
]
[]
, button [onClick (Create Widget.CounterType)] [text "Add Counter"]
, div [ style [ "display" => "flex", "flex-wrap" => "wrap" ] ]
(List.map elementView model.gifList)
]
elementView : (Int, Widget.Model) -> Html Msg
elementView (id, model) =
H.map (SubMsg id) <| Widget.view model
inputStyle : Attribute Msg
inputStyle =
style
[ ("width", "100%")
, ("height", "40px")
, ("padding", "10px 0")
, ("font-size", "2em")
, ("text-align", "center")
]
onEnter : String -> Attribute Msg
onEnter topic =
let
createOnEnter code =
if code == 13 then
Create Widget.RandomGifType
else (Topic topic)
in
on "keydown" (Json.map createOnEnter keyCode)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment