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
|
2016-04-21 12:57:58 +00:00
|
|
|
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)
|
2016-04-06 18:16:54 +00:00
|
|
|
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 =
|
2016-04-12 13:09:12 +00:00
|
|
|
Material.Model
|
2016-04-06 18:16:54 +00:00
|
|
|
|
|
|
|
|
2016-04-08 13:51:45 +00:00
|
|
|
type Square'
|
|
|
|
= Appearing
|
2016-04-12 13:09:12 +00:00
|
|
|
| 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
|
2016-04-12 13:09:12 +00:00
|
|
|
, snackbar : Snackbar.Model Int
|
2016-04-06 18:16:54 +00:00
|
|
|
, mdl : Mdl
|
2016-03-17 19:56:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
model : Model
|
|
|
|
model =
|
|
|
|
{ count = 0
|
2016-04-08 13:51:45 +00:00
|
|
|
, squares = []
|
2016-04-12 13:09:12 +00:00
|
|
|
, snackbar = Snackbar.model
|
2016-04-06 18:16:54 +00:00
|
|
|
, mdl = Material.model
|
2016-03-17 19:56:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-- ACTION, UPDATE
|
|
|
|
|
|
|
|
|
|
|
|
type Action
|
2016-04-08 13:51:45 +00:00
|
|
|
= AddSnackbar
|
2016-04-06 18:16:54 +00:00
|
|
|
| AddToast
|
2016-04-08 13:51:45 +00:00
|
|
|
| Appear Int
|
|
|
|
| Gone Int
|
2016-04-12 13:09:12 +00:00
|
|
|
| Snackbar (Snackbar.Action Int)
|
2016-04-06 18:16:54 +00:00
|
|
|
| MDL (Material.Action Action)
|
2016-03-17 19:56:04 +00:00
|
|
|
|
|
|
|
|
2016-04-12 13:09:12 +00:00
|
|
|
add : (Int -> Snackbar.Contents Int) -> Model -> (Model, Effects Action)
|
|
|
|
add f model =
|
2016-04-06 18:16:54 +00:00
|
|
|
let
|
2016-04-12 13:09:12 +00:00
|
|
|
(snackbar', fx) =
|
|
|
|
Snackbar.add (f model.count) model.snackbar
|
|
|
|
|> map2nd (Effects.map Snackbar)
|
2016-04-06 18:16:54 +00:00
|
|
|
model' =
|
|
|
|
{ model
|
2016-04-12 13:09:12 +00:00
|
|
|
| snackbar = snackbar'
|
2016-04-06 18:16:54 +00:00
|
|
|
, count = model.count + 1
|
2016-04-08 13:51:45 +00:00
|
|
|
, squares = (model.count, Appearing) :: model.squares
|
2016-04-06 18:16:54 +00:00
|
|
|
}
|
|
|
|
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
|
2016-04-06 18:16:54 +00:00
|
|
|
AddSnackbar ->
|
2016-04-12 13:09:12 +00:00
|
|
|
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 ->
|
2016-04-12 13:09:12 +00:00
|
|
|
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
|
2016-04-12 13:09:12 +00:00
|
|
|
|
|
|
|
Snackbar (Snackbar.Begin k) ->
|
2016-04-12 13:24:10 +00:00
|
|
|
model |> mapSquare k (always Active) |> pure
|
2016-04-12 13:09:12 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2016-04-12 13:09:12 +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)
|
|
|
|
|
2016-04-12 13:09:12 +00:00
|
|
|
Snackbar action' ->
|
|
|
|
Snackbar.update action' model.snackbar
|
|
|
|
|> map1st (\s -> { model | snackbar = s })
|
|
|
|
|> map2nd (Effects.map Snackbar)
|
|
|
|
|
2016-04-06 18:16:54 +00:00
|
|
|
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
|
|
|
|
2016-04-06 18:16:54 +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 =
|
2016-04-06 18:16:54 +00:00
|
|
|
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 =
|
2016-04-06 18:16:54 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2016-04-21 12:57:58 +00:00
|
|
|
transitionInner : Style
|
2016-04-12 13:24:10 +00:00
|
|
|
transitionInner =
|
2016-04-21 12:57:58 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
2016-04-21 12:57:58 +00:00
|
|
|
transitionOuter : Style
|
2016-04-12 13:24:10 +00:00
|
|
|
transitionOuter =
|
2016-04-21 12:57:58 +00:00
|
|
|
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
|
2016-04-12 13:09:12 +00:00
|
|
|
|
|
|
|
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' =
|
2016-04-12 13:09:12 +00:00
|
|
|
square == Active
|
2016-04-06 18:16:54 +00:00
|
|
|
|
2016-04-08 13:51:45 +00:00
|
|
|
(width, height, margin, selected) =
|
2016-04-12 13:09:12 +00:00
|
|
|
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. -}
|
2016-04-21 12:57:58 +00:00
|
|
|
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
|
|
|
]
|
2016-04-21 12:57:58 +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
|
2016-04-21 12:57:58 +00:00
|
|
|
-- 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
|
2016-04-08 21:05:57 +00:00
|
|
|
[ p []
|
2016-04-12 13:24:10 +00:00
|
|
|
[ text """Click the buttons below to generate toasts and snackbars. Note that
|
2016-04-08 21:05:57 +00:00
|
|
|
multiple activations are automatically queued."""
|
|
|
|
]
|
2016-04-12 13:09:12 +00:00
|
|
|
, 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
|
|
|
]
|
2016-04-12 13:09:12 +00:00
|
|
|
, Snackbar.view (Signal.forwardTo addr Snackbar) model.snackbar
|
2016-03-17 19:56:04 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
|
2016-03-21 10:04:14 +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
|
|
|
|
|
|
|
|