Add a scroll progress indicator and track the scrollTop position of your app or a specific element.
elm package install chrisbuttery/elm-scroll-progressYou can scope to a specific element (e.g. and article) or to the document.
- Import the module.
- Create a new parent Msg type referencing the
ScrollProgressMsg. - Subscribe to an incoming port, ensuring incoming data is passed back to
ScrollProgress.Progress. - Cater for the ProgressMsg in your
updatefunction. - Map emitted messages from
ScrollProgress.viewto the type teh parent view expects (Msg).
module Main exposing (..)
import ScrollProgress exposing (..)
-- MESSAGES
type Msg
= ProgressMsg ScrollProgress.Msg
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Ports.onScroll (ProgressMsg << ScrollProgress.Progress)
-- UPDATE
update : Msg -> AppModel -> ( AppModel, Cmd Msg )
update message model =
case message of
ProgressMsg subMsg ->
let
( updatedProgessModel, progressCmd ) =
ScrollProgress.update subMsg model.progressModel
in
( { model | progressModel = updatedProgessModel }, Cmd.map ProgressMsg progressCmd )
--VIEW
view : AppModel -> Html Msg
view model =
Html.div []
[ Html.App.map ProgressMsg (ScrollProgress.view model.progressModel)
, Html.h1 [] [ text "Read this " ]
, Html.div [] [ text "Some article..." ]
]Define an incoming port in your Ports.elm so JavaScript can pass in scrolling attributes.
port module Ports exposing (..)
import ProgressBar exposing (ScrollAttributes)
port onScroll : (ScrollAttributes -> msg) -> Sub msgIn your JavaScript, add an eventListener to listen for the "scroll" event on the window.
You can choose to target the document or a specifc element's targetScrollHeight.
var app = Elm.Main.embed(root);
var target = document.querySelector('.some-article');
// or target the full page height with:
// target = document.documentElement;
window.addEventListener('scroll', function() {
app.ports.onScroll.send({
scrollTop: document.documentElement.scrollTop || document.body.scrollTop,
targetScrollHeight: target.scrollHeight,
clientHeight: document.documentElement.clientHeight
});
});Note: For this to work in Firefox, we need to check for document.documentElement.scrollTop otherwise fallback to document.body.scrollTop.
All types for defining colors are Maybe String.
By default, the color of the progress scale is defined as Just #1684f6 however these String values can be whatever CSS colors you wish e.g: "#336699", "honeydew", "rgba(0,0,0,0.5)", etc.
You can choose to overide this color or include a linear gradient.
To override the color of the element, define a new model for the Child inside of the Parent.
module Main exposing (..)
import ScrollProgress exposing (..)
type alias AppModel =
{ progressModel : ScrollProgress.Model
}
newChildModel : ScrollProgress.Model
newChildModel =
{ progress = 0
, color = Just "hotpink"
, from = Nothing
, to = Nothing
}
initialModel : AppModel
initialModel =
{ progressModel = newChildModel }To replace a flat color for a linear gradient, populate the from and to properties.
newChildModel : ScrollProgress.Model
newChildModel =
{ progress = 0
, color = Nothing
, from = Just "lightseagreen"
, to = Just "lightsalmon"
}Install Create Elm App and run elm-app build or elm-app start inside of examples/article & examples/body.
Thanks goes to Michael Troy for creating the examples.
chrisbuttery.com · GitHub @chrisbuttery · Twitter @buttahz · elm-lang slack @butters