Last active
April 26, 2016 16:02
-
-
Save soupi/eed3243e4f40995442ff to your computer and use it in GitHub Desktop.
demonstration of a simple EDSL to create a slideshow in Elm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Html | |
import Html.Attributes as Html | |
import List | |
import Signal | |
import Keyboard | |
main = | |
Signal.map (render << .current) (mkSlides slides) | |
slides = | |
[ slide "Hello World" <| halign worldList | |
, slide "Second slide" <| halign <| List.reverse worldList | |
] | |
worldList = | |
[ image "http://deziretours.com/world-tours/images/world-glob.jpg" | |
, ulist | |
[ valign | |
[ text "Hello" | |
, text "World" | |
] | |
] | |
] | |
type alias State = | |
{ back : Slides | |
, current : Slide | |
, next : Slides | |
} | |
mkSlides slides = | |
let (s, ss) = | |
case slides of | |
s::ss -> (s, ss) | |
[] -> (empty, []) | |
in | |
Signal.foldp | |
moveSlide | |
{back = [], current = s, next = ss} | |
Keyboard.arrows | |
moveSlide : { x : Int, y : Int } -> State -> State | |
moveSlide {x} state = | |
let | |
updateNext state = | |
case state.next of | |
(n::ns) -> | |
{ back = state.current :: state.back | |
, current = n | |
, next = ns | |
} | |
[] -> | |
state | |
updateBack state = | |
case state.back of | |
(b::bs) -> | |
{ back = bs | |
, current = b | |
, next = state.current :: state.next | |
} | |
[] -> | |
state | |
in | |
case x of | |
-1 -> updateBack state | |
1 -> updateNext state | |
_ -> state | |
----------------- | |
-- Slides EDSL | |
----------------- | |
type alias Slides | |
= List Slide | |
type Slide | |
= Slide Element | |
type Element | |
= Empty | |
| Title String | |
| Text String | |
| Image String | |
| VAlign (List Element) | |
| HAlign (List Element) | |
| UList (List Element) | |
empty : Slide | |
empty = Slide Empty | |
slide : String -> Element -> Slide | |
slide ttl el = Slide (valign [title ttl, el]) | |
title : String -> Element | |
title str = halign [valign [text ""], Title str, valign [text ""]] | |
text : String -> Element | |
text = Text | |
image : String -> Element | |
image = Image | |
valign : List Element -> Element | |
valign = VAlign | |
halign : List Element -> Element | |
halign = HAlign | |
ulist : List Element -> Element | |
ulist = UList | |
render : Slide -> Html.Html | |
render (Slide el) = | |
Html.div [Html.style ["width" => "100%"]] [renderE el] | |
renderE : Element -> Html.Html | |
renderE element = | |
case element of | |
Empty -> | |
Html.div [] [] | |
Title tl -> | |
span [Html.h2 [Html.style ["text-align" => "center"]] [Html.text tl]] | |
Text str -> | |
span [Html.p [Html.style ["margin" => "auto"]] [Html.text str]] | |
Image url -> | |
span [Html.img [Html.src url] []] | |
VAlign els -> | |
Html.span [Html.style ["width" => "100%", "margin" => "auto"]] (applyRest block <| List.map renderE els) | |
HAlign els -> | |
Html.span [flexStyle] (List.map renderE els) | |
UList els -> | |
span [Html.ul [] (List.map ((\x -> Html.li [] [x]) << renderE) els)] | |
(=>) : a -> b -> (a, b) | |
(=>) x y = (x, y) | |
marwidStyle = | |
Html.style | |
[ "display" => "inline-block" | |
, "margin" => "auto" | |
] | |
flexStyle = | |
Html.style | |
[ "display" => "flex" | |
, "flex-flow" => "row wrap" | |
] | |
span x = | |
Html.span [marwidStyle] x | |
block x = | |
Html.span [Html.style ["display" => "block"]] [x] | |
applyRest f xs = | |
case xs of | |
(x::xs) -> x :: List.map f xs | |
_ -> xs |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment