Last active
November 26, 2020 23:56
-
-
Save ryan-haskell/b26c0d6a5d2bfd74643e7da6543c5170 to your computer and use it in GitHub Desktop.
an example of a component built around a data structure.
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
module Components.Carousel exposing | |
( Carousel | |
, create | |
, next | |
, previous | |
, select | |
, view | |
) | |
import Array | |
import Html exposing (..) | |
import Html.Events as Events | |
import Html.Attributes exposing (class) | |
type Carousel slide | |
= Carousel (Internals slide) | |
type alias Internals slide = | |
{ index : Int | |
, first : slide -- guarantees at least one element | |
, others : List slide | |
} | |
create : slide -> List slide -> Carousel slide | |
create first others = | |
Carousel | |
{ index = 0 | |
, first = first | |
, others = others | |
} | |
next : Carousel slide -> Carousel slide | |
next (Carousel internals) = | |
Carousel | |
{ internals | index = modBy (length internals) (internals.index + 1) } | |
previous : Carousel slide -> Carousel slide | |
previous (Carousel internals) = | |
Carousel | |
{ internals | index = modBy (length internals) (internals.index - 1) } | |
select : Int -> Carousel slide -> Carousel slide | |
select index (Carousel internals) = | |
if index >= length internals then | |
Carousel internals | |
-- no update if out of bounds | |
else | |
Carousel { internals | index = index } | |
view : | |
{ carousel : Carousel slide | |
, onNext : msg | |
, onPrevious : msg | |
, onSelect : Int -> msg | |
, viewSlide : slide -> Html msg | |
} | |
-> Html msg | |
view options = | |
let | |
(Carousel internals) = | |
options.carousel | |
in | |
div [ class "carousel" ] | |
[ options.viewSlide (current internals) | |
, div [ class "controls" ] | |
[ button [ Events.onClick options.onPrevious ] [ text "Previous" ] | |
, div [ class "dots" ] | |
(List.range 0 (length internals - 1) | |
|> List.map (\index -> button [ class "dot", Events.onClick (options.onSelect index) ] []) | |
) | |
, button [ Events.onClick options.onNext ] [ text "Next" ] | |
] | |
] | |
-- INTERNALS | |
length : Internals slide -> Int | |
length { first, others } = | |
List.length (first :: others) | |
current : Internals slide -> slide | |
current { index, first, others } = | |
Array.fromList (first :: others) | |
|> Array.get index | |
|> Maybe.withDefault first |
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
module Main exposing (main) | |
import Html exposing (..) | |
import Html.Attributes exposing (class) | |
import Components.Carousel as Carousel exposing (Carousel) | |
-- INIT | |
type alias Model = | |
{ testimonials : Carousel Testimonial | |
} | |
type alias Testimonial = | |
{ quote : String | |
, author : String | |
} | |
init : Model | |
init = | |
{ testimonials = | |
Carousel.create | |
{ quote = "Cats have ears", author = "Ryan" } | |
[ { quote = "Dogs also have ears", author = "Alexa" } | |
, { quote = "I have ears", author = "Erik" } | |
] | |
} | |
-- UPDATE | |
type Msg | |
= NextTestimonial | |
| PreviousTestimonial | |
| SelectTestimonial Int | |
update : Msg -> Model -> Model | |
update msg model = | |
case msg of | |
NextTestimonial -> | |
{ model | testimonials = Carousel.next model.testimonials } | |
PreviousTestimonial -> | |
{ model | testimonials = Carousel.previous model.testimonials } | |
SelectTestimonial index -> | |
{ model | testimonials = Carousel.select index model.testimonials } | |
-- VIEW | |
view : Model -> Html Msg | |
view model = | |
div [ class "page" ] | |
[ Carousel.view | |
{ carousel = model.testimonials | |
, onNext = NextTestimonial | |
, onPrevious = PreviousTestimonial | |
, onSelect = SelectTestimonial | |
, viewSlide = viewTestimonial | |
} | |
] | |
viewTestimonial : Testimonial -> Html msg | |
viewTestimonial options = | |
div [ class "testimonial" ] | |
[ p [ class "quote" ] [ text options.quote ] | |
, p [ class "author" ] [ text options.author ] | |
] | |
-- MAIN | |
main : Program () Model Msg | |
main = | |
Browser.sandbox | |
{ init = init | |
, update = update | |
, view = view | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment