elm-mdl/demo/Demo/Snackbar.elm

322 lines
7.9 KiB
Elm
Raw Normal View History

2016-03-17 19:56:04 +00:00
module Demo.Snackbar where
import Effects exposing (Effects, none)
import Html exposing (..)
import Html.Attributes exposing (class, style, key)
import Array exposing (Array)
2016-04-08 13:51:45 +00:00
import Time exposing (Time, millisecond)
2016-03-17 19:56:04 +00:00
2016-04-12 13:24:10 +00:00
import Material.Helpers exposing (map1st, map2nd, pure, delay)
2016-03-19 22:47:21 +00:00
import Material.Color as Color
import Material.Style as Style exposing (cs, css, Style)
2016-03-17 19:56:04 +00:00
import Material.Snackbar as Snackbar
import Material.Button as Button exposing (Action(..))
import Material.Grid exposing (..)
2016-04-12 21:39:35 +00:00
import Material.Elevation exposing (e2, e8)
import Material
2016-03-17 19:56:04 +00:00
2016-03-30 07:19:18 +00:00
import Demo.Page as Page
2016-03-17 19:56:04 +00:00
2016-04-12 13:24:10 +00:00
2016-03-17 19:56:04 +00:00
-- MODEL
2016-04-12 13:24:10 +00:00
2016-04-07 07:52:11 +00:00
type alias Mdl =
Material.Model
2016-04-08 13:51:45 +00:00
type Square'
= Appearing
| Waiting
| Active
2016-04-08 13:51:45 +00:00
| Idle
| Disappearing
type alias Square =
(Int, Square')
2016-03-17 19:56:04 +00:00
type alias Model =
{ count : Int
2016-04-08 13:51:45 +00:00
, squares : List Square
, snackbar : Snackbar.Model Int
, mdl : Mdl
2016-03-17 19:56:04 +00:00
}
model : Model
model =
{ count = 0
2016-04-08 13:51:45 +00:00
, squares = []
, snackbar = Snackbar.model
, mdl = Material.model
2016-03-17 19:56:04 +00:00
}
-- ACTION, UPDATE
type Action
2016-04-08 13:51:45 +00:00
= AddSnackbar
| AddToast
2016-04-08 13:51:45 +00:00
| Appear Int
| Gone Int
| Snackbar (Snackbar.Action Int)
| MDL (Material.Action Action)
2016-03-17 19:56:04 +00:00
add : (Int -> Snackbar.Contents Int) -> Model -> (Model, Effects Action)
add f model =
let
(snackbar', fx) =
Snackbar.add (f model.count) model.snackbar
|> map2nd (Effects.map Snackbar)
model' =
{ model
| snackbar = snackbar'
, count = model.count + 1
2016-04-08 13:51:45 +00:00
, squares = (model.count, Appearing) :: model.squares
}
in
2016-04-08 13:51:45 +00:00
( model'
, Effects.batch
[ Effects.tick (always (Appear model.count))
, fx
]
)
mapSquare : Int -> (Square' -> Square') -> Model -> Model
mapSquare k f model =
{ model
| squares =
List.map
( \((k', sq) as s) -> if k /= k' then s else (k', f sq) )
model.squares
}
2016-03-17 19:56:04 +00:00
update : Action -> Model -> (Model, Effects Action)
update action model =
case action of
AddSnackbar ->
add (\k -> Snackbar.snackbar k ("Snackbar message #" ++ toString k) "UNDO") model
2016-03-17 19:56:04 +00:00
2016-04-07 07:52:11 +00:00
AddToast ->
add (\k -> Snackbar.toast k <| "Toast message #" ++ toString k) model
2016-03-17 19:56:04 +00:00
2016-04-08 13:51:45 +00:00
Appear k ->
2016-04-12 13:24:10 +00:00
model |> mapSquare k (\sq -> if sq == Appearing then Waiting else sq) |> pure
Snackbar (Snackbar.Begin k) ->
2016-04-12 13:24:10 +00:00
model |> mapSquare k (always Active) |> pure
Snackbar (Snackbar.End k) ->
2016-04-12 13:24:10 +00:00
model |> mapSquare k (always Idle) |> pure
2016-04-08 13:51:45 +00:00
Snackbar (Snackbar.Click k) ->
2016-04-08 13:51:45 +00:00
( model |> mapSquare k (always Disappearing)
, delay transitionLength (Gone k)
)
Gone k ->
2016-03-17 19:56:04 +00:00
({ model
2016-04-08 13:51:45 +00:00
| squares = List.filter (fst >> (/=) k) model.squares
2016-03-17 19:56:04 +00:00
}
, none)
Snackbar action' ->
Snackbar.update action' model.snackbar
|> map1st (\s -> { model | snackbar = s })
|> map2nd (Effects.map Snackbar)
MDL action' ->
Material.update MDL action' model.mdl
|> map1st (\m -> { model | mdl = m })
2016-03-17 19:56:04 +00:00
2016-04-07 07:52:11 +00:00
2016-04-08 13:51:45 +00:00
-- VIEW
2016-03-17 19:56:04 +00:00
2016-04-12 13:24:10 +00:00
2016-04-07 07:52:11 +00:00
addSnackbarButton : Button.Instance Mdl Action
addSnackbarButton =
Button.instance 0 MDL
Button.raised (Button.model True)
[ Button.fwdClick AddSnackbar ]
2016-04-07 07:52:11 +00:00
addToastButton : Button.Instance Mdl Action
addToastButton =
Button.instance 1 MDL
Button.raised (Button.model True)
[ Button.fwdClick AddToast ]
2016-04-08 13:51:45 +00:00
boxHeight : String
boxHeight = "48px"
boxWidth : String
boxWidth = "64px"
transitionLength : Time
transitionLength = 150 * millisecond
transitionInner : Style
2016-04-12 13:24:10 +00:00
transitionInner =
css "transition"
<| "box-shadow 333ms ease-in-out 0s, "
++ "width " ++ toString transitionLength ++ "ms, "
++ "height " ++ toString transitionLength ++ "ms, "
++ "background-color " ++ toString transitionLength ++ "ms"
2016-04-08 13:51:45 +00:00
transitionOuter : Style
2016-04-12 13:24:10 +00:00
transitionOuter =
css "transition"
<| "width " ++ toString transitionLength ++ "ms ease-in-out 0s, "
++ "margin " ++ toString transitionLength ++ "ms ease-in-out 0s"
2016-04-12 13:24:10 +00:00
2016-04-08 13:51:45 +00:00
clickView : Model -> Square -> Html
clickView model (k, square) =
2016-03-17 19:56:04 +00:00
let
2016-04-12 21:03:13 +00:00
hue =
Array.get ((k + 4) % Array.length Color.hues) Color.hues
2016-03-19 22:47:21 +00:00
|> Maybe.withDefault Color.Teal
shade =
case square of
Idle ->
Color.S100
_ ->
Color.S500
color =
2016-04-12 21:03:13 +00:00
Color.color hue shade
2016-03-19 22:47:21 +00:00
2016-04-08 13:51:45 +00:00
selected' =
square == Active
2016-04-08 13:51:45 +00:00
(width, height, margin, selected) =
if square == Appearing || square == Disappearing then
("0", "0", "16px 0", False)
else
(boxWidth, boxHeight, "16px 16px", selected')
2016-03-17 19:56:04 +00:00
in
2016-04-12 13:24:10 +00:00
{- In order to get the box appearance and disappearance animations
to start in the lower-left corner, we render boxes as an outer div
(which animates only width, to cause reflow of surrounding boxes),
and an absolutely positioned inner div (to force animation to start
in the lower-left corner. -}
Style.div
[ css "height" boxHeight
, css "width" width
, css "position" "relative"
, css "display" "inline-block"
, css "margin" margin
, css "z-index" "0"
, transitionOuter
, Style.attribute (key <| toString k)
{- Interestingly, not setting key messes up CSS transitions in
spectacular ways. -}
2016-03-17 19:56:04 +00:00
]
[ Style.div
2016-04-08 13:51:45 +00:00
[ Color.background color
, Color.text Color.primaryContrast
2016-04-12 21:39:35 +00:00
, if selected then e8 else e2
-- Center contents
, css "display" "inline-flex"
, css "align-items" "center"
, css "justify-content" "center"
, css "flex" "0 0 auto"
-- Sizing
, css "height" height
, css "width" width
, css "border-radius" "2px"
, css "box-sizing" "border-box"
-- Force appearance/disapparenace to be from/to lower-left corner.
, css "position" "absolute"
, css "bottom" "0"
, css "left" "0"
-- Transitions
, transitionInner
2016-04-08 13:51:45 +00:00
]
[ div [] [ text <| toString k ] ]
]
2016-03-17 19:56:04 +00:00
2016-03-19 22:47:21 +00:00
2016-03-17 19:56:04 +00:00
view : Signal.Address Action -> Model -> Html
view addr model =
2016-04-12 14:37:16 +00:00
Page.body2 "Snackbar & Toast" srcUrl intro references
[ p []
2016-04-12 13:24:10 +00:00
[ text """Click the buttons below to generate toasts and snackbars. Note that
multiple activations are automatically queued."""
]
, grid [ ]
2016-04-08 13:51:45 +00:00
[ cell
2016-04-12 14:37:16 +00:00
[ size All 4, size Desktop 2]
[ addSnackbarButton.view addr model.mdl
2016-04-08 13:51:45 +00:00
[ Button.colored
2016-04-12 14:37:16 +00:00
, css "width" "8em"
2016-04-08 13:51:45 +00:00
]
2016-04-12 14:37:16 +00:00
[ text "Snackbar" ]
2016-03-17 19:56:04 +00:00
]
2016-03-31 19:58:30 +00:00
, cell
2016-04-12 14:37:16 +00:00
[ size All 4, size Desktop 2]
[ addToastButton.view addr model.mdl
2016-04-08 13:51:45 +00:00
[ Button.colored
2016-04-12 14:37:16 +00:00
, css "width" "8em"
2016-04-08 13:51:45 +00:00
]
2016-04-12 14:37:16 +00:00
[ text "Toast" ]
2016-03-17 19:56:04 +00:00
]
, cell
2016-04-12 14:37:16 +00:00
[ size Desktop 10, offset Desktop 1
, size Tablet 6, offset Tablet 1
2016-04-08 13:51:45 +00:00
, size Phone 4
, align Top
2016-04-12 14:37:16 +00:00
, css "padding-top" "32px"
2016-04-08 13:51:45 +00:00
]
(model.squares |> List.reverse |> List.map (clickView model))
2016-03-17 19:56:04 +00:00
]
, Snackbar.view (Signal.forwardTo addr Snackbar) model.snackbar
2016-03-17 19:56:04 +00:00
]
intro : Html
2016-03-30 07:19:18 +00:00
intro =
Page.fromMDL "https://www.getmdl.io/components/index.html#snackbar-section" """
2016-03-17 19:56:04 +00:00
> The Material Design Lite (MDL) __snackbar__ component is a container used to
> notify a user of an operation's status. It displays at the bottom of the
> screen. A snackbar may contain an action button to execute a command for the
> user. Actions should undo the committed action or retry it if it failed for
> example. Actions should not be to close the snackbar. By not providing an
> action, the snackbar becomes a __toast__ component.
2016-03-30 07:19:18 +00:00
"""
2016-03-17 19:56:04 +00:00
2016-03-31 19:58:30 +00:00
2016-03-30 07:19:18 +00:00
srcUrl : String
srcUrl =
2016-04-12 22:21:31 +00:00
"https://github.com/debois/elm-mdl/blob/master/demo/Demo/Snackbar.elm"
2016-03-17 19:56:04 +00:00
2016-03-31 19:58:30 +00:00
2016-03-30 07:19:18 +00:00
references : List (String, String)
references =
2016-03-31 19:58:30 +00:00
[ Page.package "http://package.elm-lang.org/packages/debois/elm-mdl/latest/Material-Snackbar"
2016-03-30 07:19:18 +00:00
, Page.mds "https://www.google.com/design/spec/components/snackbars-toasts.html"
, Page.mdl "https://www.getmdl.io/components/index.html#snackbar-section"
]
2016-03-17 19:56:04 +00:00