mirror of
https://github.com/ryannhg/elm-spa.git
synced 2024-11-22 09:44:55 +03:00
add back in transitions
This commit is contained in:
parent
ce090e7253
commit
44cf861672
@ -9,7 +9,8 @@ import Layout as Layout
|
||||
main : Application () Pages.Model Pages.Msg
|
||||
main =
|
||||
Application.create
|
||||
{ routing =
|
||||
{ transition = Application.fade 200
|
||||
, routing =
|
||||
{ fromUrl = Route.fromUrl
|
||||
, toPath = Route.toPath
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ module Pages.Counter exposing
|
||||
|
||||
import Application
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (href)
|
||||
import Html.Events as Events
|
||||
|
||||
|
||||
@ -59,5 +58,4 @@ view model =
|
||||
, p [] [ text (String.fromInt model.counter) ]
|
||||
, button [ Events.onClick Increment ] [ text "+" ]
|
||||
]
|
||||
, a [ href "/#section" ] [ text "Bottom of homepage" ]
|
||||
]
|
||||
|
@ -7,7 +7,6 @@ module Pages.Homepage exposing
|
||||
|
||||
import Application
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (href, id, style)
|
||||
|
||||
|
||||
type alias Model =
|
||||
@ -34,8 +33,4 @@ view =
|
||||
div []
|
||||
[ h1 [] [ text "Homepage" ]
|
||||
, p [] [ text "How exciting!" ]
|
||||
, a [ href "#section" ] [ text "scroll bois" ]
|
||||
, div [ style "height" "200vh" ] []
|
||||
, h3 [ id "section" ] [ text "hey thur" ]
|
||||
, p [] [ text "How exciting!" ]
|
||||
]
|
||||
|
@ -5,6 +5,8 @@ module Application exposing
|
||||
, Static, static
|
||||
, Sandbox, sandbox
|
||||
, Element, element
|
||||
, Transition, fade
|
||||
, none
|
||||
)
|
||||
|
||||
{-|
|
||||
@ -24,6 +26,8 @@ module Application exposing
|
||||
|
||||
@docs ElementWithParams, elementWithParams
|
||||
|
||||
@docs Transition, fade
|
||||
|
||||
-}
|
||||
|
||||
import Browser
|
||||
@ -31,6 +35,8 @@ import Browser.Dom as Dom
|
||||
import Browser.Navigation as Nav
|
||||
import Html exposing (Html)
|
||||
import Internals.Page as Page
|
||||
import Internals.Transition as Transition exposing (Transitionable)
|
||||
import Internals.Utils as Utils
|
||||
import Task
|
||||
import Url exposing (Url)
|
||||
|
||||
@ -48,6 +54,7 @@ create :
|
||||
{ fromUrl : Url -> route
|
||||
, toPath : route -> String
|
||||
}
|
||||
, transition : Transition (Html msg)
|
||||
, layout :
|
||||
{ view : { page : Html msg } -> Html msg
|
||||
}
|
||||
@ -59,17 +66,23 @@ create :
|
||||
}
|
||||
-> Application flags model msg
|
||||
create config =
|
||||
let
|
||||
transition =
|
||||
unwrap config.transition
|
||||
in
|
||||
Browser.application
|
||||
{ init =
|
||||
init
|
||||
{ init = config.pages.init
|
||||
, fromUrl = config.routing.fromUrl
|
||||
, speed = transition.speed
|
||||
}
|
||||
, update =
|
||||
update
|
||||
{ fromUrl = config.routing.fromUrl
|
||||
, init = config.pages.init
|
||||
, update = config.pages.update
|
||||
, speed = transition.speed
|
||||
}
|
||||
, subscriptions =
|
||||
subscriptions
|
||||
@ -79,6 +92,7 @@ create config =
|
||||
view
|
||||
{ view = config.pages.bundle >> .view
|
||||
, layout = config.layout.view
|
||||
, transition = transition.strategy transition.speed
|
||||
}
|
||||
, onUrlChange = Url
|
||||
, onUrlRequest = Link
|
||||
@ -93,13 +107,14 @@ type alias Model flags model =
|
||||
{ url : Url
|
||||
, flags : flags
|
||||
, key : Nav.Key
|
||||
, page : model
|
||||
, page : Transitionable model
|
||||
}
|
||||
|
||||
|
||||
init :
|
||||
{ fromUrl : Url -> route
|
||||
, init : route -> ( model, Cmd msg )
|
||||
, speed : Int
|
||||
}
|
||||
-> flags
|
||||
-> Url
|
||||
@ -110,8 +125,19 @@ init config flags url key =
|
||||
|> config.fromUrl
|
||||
|> config.init
|
||||
|> Tuple.mapBoth
|
||||
(\page -> { flags = flags, url = url, key = key, page = page })
|
||||
(handleJumpLinks url)
|
||||
(\page ->
|
||||
{ flags = flags
|
||||
, url = url
|
||||
, key = key
|
||||
, page = Transition.Ready page
|
||||
}
|
||||
)
|
||||
(\cmd ->
|
||||
Cmd.batch
|
||||
[ handleJumpLinks url cmd
|
||||
, Utils.delay config.speed TransitionComplete
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
handleJumpLinks : Url -> Cmd msg -> Cmd (Msg msg)
|
||||
@ -143,7 +169,9 @@ scrollTo =
|
||||
type Msg msg
|
||||
= Url Url
|
||||
| Link Browser.UrlRequest
|
||||
| TransitionTo Url
|
||||
| ScrollComplete
|
||||
| TransitionComplete
|
||||
| Page msg
|
||||
|
||||
|
||||
@ -151,6 +179,7 @@ update :
|
||||
{ fromUrl : Url -> route
|
||||
, init : route -> ( model, Cmd msg )
|
||||
, update : msg -> model -> ( model, Cmd msg )
|
||||
, speed : Int
|
||||
}
|
||||
-> Msg msg
|
||||
-> Model flags model
|
||||
@ -160,23 +189,13 @@ update config msg model =
|
||||
ScrollComplete ->
|
||||
( model, Cmd.none )
|
||||
|
||||
Url url ->
|
||||
url
|
||||
|> config.fromUrl
|
||||
|> config.init
|
||||
|> Tuple.mapBoth
|
||||
(\page -> { model | url = url, page = page })
|
||||
(handleJumpLinks url)
|
||||
|
||||
Link (Browser.Internal url) ->
|
||||
if url.path == model.url.path then
|
||||
( model
|
||||
, Nav.load (Url.toString url)
|
||||
)
|
||||
if url == model.url then
|
||||
( model, Cmd.none )
|
||||
|
||||
else
|
||||
( model
|
||||
, Nav.pushUrl model.key (Url.toString url)
|
||||
( { model | page = Transition.begin model.page }
|
||||
, Utils.delay config.speed (TransitionTo url)
|
||||
)
|
||||
|
||||
Link (Browser.External url) ->
|
||||
@ -184,11 +203,33 @@ update config msg model =
|
||||
, Nav.load url
|
||||
)
|
||||
|
||||
TransitionTo url ->
|
||||
( model
|
||||
, if url.path == model.url.path then
|
||||
Nav.load (Url.toString url)
|
||||
|
||||
else
|
||||
Nav.pushUrl model.key (Url.toString url)
|
||||
)
|
||||
|
||||
TransitionComplete ->
|
||||
( { model | page = Transition.complete model.page }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Url url ->
|
||||
url
|
||||
|> config.fromUrl
|
||||
|> config.init
|
||||
|> Tuple.mapBoth
|
||||
(\page -> { model | url = url, page = Transition.Complete page })
|
||||
(handleJumpLinks url)
|
||||
|
||||
Page pageMsg ->
|
||||
Tuple.mapBoth
|
||||
(\page -> { model | page = page })
|
||||
(\page -> { model | page = Transition.Complete page })
|
||||
(Cmd.map Page)
|
||||
(config.update pageMsg model.page)
|
||||
(config.update pageMsg (Transition.unwrap model.page))
|
||||
|
||||
|
||||
|
||||
@ -200,7 +241,7 @@ subscriptions :
|
||||
-> Model flags model
|
||||
-> Sub (Msg msg)
|
||||
subscriptions config model =
|
||||
Sub.map Page (config.subscriptions model.page)
|
||||
Sub.map Page (config.subscriptions (Transition.unwrap model.page))
|
||||
|
||||
|
||||
|
||||
@ -209,17 +250,33 @@ subscriptions config model =
|
||||
|
||||
view :
|
||||
{ view : model -> Html msg
|
||||
, transition : Transition.Options (Html msg)
|
||||
, layout : { page : Html msg } -> Html msg
|
||||
}
|
||||
-> Model flags model
|
||||
-> Browser.Document (Msg msg)
|
||||
view config model =
|
||||
{ title = "App title"
|
||||
{ title = "elm-app demo"
|
||||
, body =
|
||||
[ Html.map Page <|
|
||||
config.layout
|
||||
{ page = config.view model.page
|
||||
}
|
||||
case model.page of
|
||||
Transition.Ready page ->
|
||||
config.transition.beforeLoad
|
||||
{ layout = config.layout
|
||||
, page = config.view page
|
||||
}
|
||||
|
||||
Transition.Transitioning page ->
|
||||
config.transition.leavingPage
|
||||
{ layout = config.layout
|
||||
, page = config.view page
|
||||
}
|
||||
|
||||
Transition.Complete page ->
|
||||
config.transition.enteringPage
|
||||
{ layout = config.layout
|
||||
, page = config.view page
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -276,3 +333,43 @@ element :
|
||||
-> Page params pageModel pageMsg model msg
|
||||
element =
|
||||
Page.element
|
||||
|
||||
|
||||
|
||||
-- TRANSITIONS
|
||||
|
||||
|
||||
type Transition view
|
||||
= Using (TransitionInfo view)
|
||||
| None
|
||||
|
||||
|
||||
type alias TransitionInfo view =
|
||||
{ speed : Int
|
||||
, strategy : Transition.Strategy view
|
||||
}
|
||||
|
||||
|
||||
unwrap : Transition a -> TransitionInfo a
|
||||
unwrap transition =
|
||||
case transition of
|
||||
Using value ->
|
||||
value
|
||||
|
||||
None ->
|
||||
{ speed = 0
|
||||
, strategy = Transition.none
|
||||
}
|
||||
|
||||
|
||||
fade : Int -> Transition (Html msg)
|
||||
fade speed =
|
||||
Using
|
||||
{ speed = speed
|
||||
, strategy = Transition.fade
|
||||
}
|
||||
|
||||
|
||||
none : Transition a
|
||||
none =
|
||||
None
|
||||
|
116
src/Internals/Transition.elm
Normal file
116
src/Internals/Transition.elm
Normal file
@ -0,0 +1,116 @@
|
||||
module Internals.Transition exposing
|
||||
( Transitionable(..), unwrap, begin, complete
|
||||
, Strategy, Options, fade, none
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs Transitionable, unwrap, begin, complete
|
||||
|
||||
@docs Strategy, Options, fade, none
|
||||
|
||||
-}
|
||||
|
||||
import Html exposing (Html, div)
|
||||
import Html.Attributes as Attr
|
||||
|
||||
|
||||
type Transitionable a
|
||||
= Ready a
|
||||
| Transitioning a
|
||||
| Complete a
|
||||
|
||||
|
||||
unwrap : Transitionable a -> a
|
||||
unwrap transitionable =
|
||||
case transitionable of
|
||||
Ready value ->
|
||||
value
|
||||
|
||||
Transitioning value ->
|
||||
value
|
||||
|
||||
Complete value ->
|
||||
value
|
||||
|
||||
|
||||
begin : Transitionable a -> Transitionable a
|
||||
begin =
|
||||
unwrap >> Transitioning
|
||||
|
||||
|
||||
complete : Transitionable a -> Transitionable a
|
||||
complete =
|
||||
unwrap >> Complete
|
||||
|
||||
|
||||
type alias Options view =
|
||||
{ beforeLoad : Views view -> view
|
||||
, leavingPage : Views view -> view
|
||||
, enteringPage : Views view -> view
|
||||
}
|
||||
|
||||
|
||||
type alias Views view =
|
||||
{ layout : { page : view } -> view
|
||||
, page : view
|
||||
}
|
||||
|
||||
|
||||
type alias Strategy view =
|
||||
Int -> Options view
|
||||
|
||||
|
||||
fade : Strategy (Html msg)
|
||||
fade speed =
|
||||
let
|
||||
transition =
|
||||
"opacity " ++ String.fromInt speed ++ "ms"
|
||||
|
||||
styles =
|
||||
{ invisible =
|
||||
[ Attr.style "height" "100%"
|
||||
, Attr.style "opacity" "0"
|
||||
, Attr.style "transition" transition
|
||||
]
|
||||
, visible =
|
||||
[ Attr.style "height" "100%"
|
||||
, Attr.style "opacity" "1"
|
||||
, Attr.style "transition" transition
|
||||
]
|
||||
}
|
||||
in
|
||||
{ beforeLoad =
|
||||
\{ layout, page } ->
|
||||
div styles.invisible
|
||||
[ layout
|
||||
{ page = div styles.invisible [ page ]
|
||||
}
|
||||
]
|
||||
, leavingPage =
|
||||
\{ layout, page } ->
|
||||
div styles.visible
|
||||
[ layout
|
||||
{ page = div styles.invisible [ page ]
|
||||
}
|
||||
]
|
||||
, enteringPage =
|
||||
\{ layout, page } ->
|
||||
div styles.visible
|
||||
[ layout
|
||||
{ page = div styles.visible [ page ]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
none : Strategy a
|
||||
none _ =
|
||||
let
|
||||
view { layout, page } =
|
||||
layout { page = page }
|
||||
in
|
||||
{ beforeLoad = view
|
||||
, leavingPage = view
|
||||
, enteringPage = view
|
||||
}
|
10
src/Internals/Utils.elm
Normal file
10
src/Internals/Utils.elm
Normal file
@ -0,0 +1,10 @@
|
||||
module Internals.Utils exposing (delay)
|
||||
|
||||
import Process
|
||||
import Task
|
||||
|
||||
|
||||
delay : Int -> msg -> Cmd msg
|
||||
delay ms msg =
|
||||
Process.sleep (toFloat ms)
|
||||
|> Task.perform (\_ -> msg)
|
Loading…
Reference in New Issue
Block a user