diff --git a/.gitignore b/.gitignore index 2f93cb4..29f6dbf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store ./dist -elm-stuff/0.19.1 +elm-stuff +!elm-stuff/.elm-spa ./node_modules \ No newline at end of file diff --git a/README.md b/README.md index e261c57..b2255dc 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ > for building single page apps -## run the example! +## local development ``` -npm run example +npm run dev ``` + diff --git a/elm-analyse.json b/elm-analyse.json new file mode 100644 index 0000000..9794de7 --- /dev/null +++ b/elm-analyse.json @@ -0,0 +1,6 @@ +{ + "checks" : { + "SingleFieldRecord": false, + "ImportAll": false + } +} \ No newline at end of file diff --git a/elm.json b/elm.json index 0ac93ab..ca0a5ac 100644 --- a/elm.json +++ b/elm.json @@ -1,20 +1,21 @@ { - "type": "package", - "name": "ryannhg/elm-app", - "summary": "a way to build single page apps with Elm", - "license": "BSD-3-Clause", - "version": "1.0.0", - "exposed-modules": [ - "App", - "App.Page", - "App.Types" - ], - "elm-version": "0.19.0 <= v < 0.20.0", - "dependencies": { - "elm/browser": "1.0.0 <= v < 2.0.0", - "elm/core": "1.0.0 <= v < 2.0.0", - "elm/html": "1.0.0 <= v < 2.0.0", - "elm/url": "1.0.0 <= v < 2.0.0" - }, - "test-dependencies": {} -} \ No newline at end of file + "type": "package", + "name": "ryannhg/elm-app", + "summary": "a way to build single page apps with Elm", + "license": "BSD-3-Clause", + "version": "1.0.0", + "exposed-modules": [ + "App", + "App.Page", + "App.Types" + ], + "elm-version": "0.19.0 <= v < 0.20.0", + "dependencies": { + "elm/browser": "1.0.0 <= v < 2.0.0", + "elm/core": "1.0.0 <= v < 2.0.0", + "elm/html": "1.0.0 <= v < 2.0.0", + "elm/url": "1.0.0 <= v < 2.0.0", + "mdgriffith/elm-ui": "1.1.5 <= v < 2.0.0" + }, + "test-dependencies": {} +} diff --git a/examples/complex/elm.json b/examples/complex/elm.json index 9442704..97ed1ab 100644 --- a/examples/complex/elm.json +++ b/examples/complex/elm.json @@ -3,7 +3,7 @@ "source-directories": [ "src", "../../src", - "elm-stuff/.generated" + "elm-stuff/.elm-spa" ], "elm-version": "0.19.1", "dependencies": { diff --git a/examples/complex/src/Main.elm b/examples/complex/src/Main.elm index 02fef4c..c65d6c1 100644 --- a/examples/complex/src/Main.elm +++ b/examples/complex/src/Main.elm @@ -1,6 +1,7 @@ module Main exposing (main) import App +import App.Transition as Transition import Element import Generated.Pages as Pages import Generated.Routes as Routes @@ -15,7 +16,8 @@ main = , map = Element.map } , routing = - { routes = Routes.parsers + { transition = Transition.fadeUi 300 + , routes = Routes.parsers , toPath = Routes.toPath , notFound = Routes.routes.notFound } diff --git a/src/App.elm b/src/App.elm index 0f35197..7c8bd8e 100644 --- a/src/App.elm +++ b/src/App.elm @@ -11,8 +11,6 @@ module App exposing `App.create` replaces [Browser.application](https://package.elm-lang.org/packages/elm/browser/latest/Browser#application) as the entrypoint to your app. - module Main exposing (main) - import App import Global import Pages @@ -63,6 +61,7 @@ import Browser import Browser.Navigation as Nav import Html exposing (Html) import Internals.Page as Page +import Internals.Transition as Transition exposing (Transition) import Internals.Utils as Utils import Url exposing (Url) import Url.Parser as Parser exposing (Parser) @@ -114,7 +113,8 @@ create : , map : (layoutMsg -> Msg globalMsg layoutMsg) -> ui_layoutMsg -> ui_msg } , routing : - { routes : List (Parser (route -> route) route) + { transition : Transition ui_msg + , routes : List (Parser (route -> route) route) , toPath : route -> String , notFound : route } @@ -154,6 +154,7 @@ create config = , routing = { fromUrl = fromUrl config.routing , toPath = config.routing.toPath + , transition = config.routing.transition } } , update = @@ -180,6 +181,7 @@ create config = { toHtml = config.ui.toHtml , bundle = page.bundle , map = config.ui.map + , transition = config.routing.transition } , onUrlChange = ChangedUrl , onUrlRequest = ClickedLink @@ -210,6 +212,10 @@ type alias Model flags globalModel model = , key : Nav.Key , global : globalModel , page : model + , visibilities : + { layout : Transition.Visibility + , page : Transition.Visibility + } } @@ -217,6 +223,7 @@ init : { routing : { fromUrl : Url -> route , toPath : route -> String + , transition : Transition ui_msg } , init : { global : @@ -249,11 +256,16 @@ init config flags url key = , key = key , global = globalModel , page = pageModel + , visibilities = + { layout = Transition.invisible + , page = Transition.visible + } } , Cmd.batch [ Cmd.map Page pageCmd , Cmd.map Global pageGlobalCmd , Cmd.map Global globalCmd + , Utils.delay (Transition.speed config.routing.transition) FadeInLayout , cmd ] ) @@ -269,6 +281,7 @@ type Msg globalMsg msg | ClickedLink Browser.UrlRequest | Global globalMsg | Page msg + | FadeInLayout update : @@ -295,6 +308,16 @@ update : -> ( Model flags globalModel layoutModel, Cmd (Msg globalMsg layoutMsg) ) update config msg model = case msg of + FadeInLayout -> + ( { model + | visibilities = + { layout = Transition.visible + , page = model.visibilities.page + } + } + , Cmd.none + ) + ClickedLink (Browser.Internal url) -> if url == model.url then ( model, Cmd.none ) @@ -395,6 +418,7 @@ view : , bundle : layoutModel -> Page.Bundle layoutMsg ui_layoutMsg globalModel globalMsg (Msg globalMsg layoutMsg) ui_msg + , transition : Transition ui_msg } -> Model flags globalModel layoutModel -> Browser.Document (Msg globalMsg layoutMsg) @@ -411,6 +435,10 @@ view config model = in { title = bundle.title , body = - [ config.toHtml bundle.view + [ config.toHtml <| + Transition.view + config.transition + model.visibilities.layout + { layout = identity, page = bundle.view } ] } diff --git a/src/App/Transition.elm b/src/App/Transition.elm new file mode 100644 index 0000000..6807dc1 --- /dev/null +++ b/src/App/Transition.elm @@ -0,0 +1,43 @@ +module App.Transition exposing + ( Transition + , optOut, none, fadeHtml, fadeUi + ) + +{-| + +@docs Transition +@docs optOut, none, fadeHtml, fadeUi + +-} + +import Element exposing (Element) +import Html exposing (Html) +import Internals.Transition + + +type alias Transition ui_msg = + Internals.Transition.Transition ui_msg + + + +-- TRANSITIONS + + +optOut : Transition ui_msg +optOut = + Internals.Transition.optOut + + +none : Transition ui_msg +none = + Internals.Transition.none + + +fadeHtml : Int -> Transition (Html msg) +fadeHtml = + Internals.Transition.fadeHtml + + +fadeUi : Int -> Transition (Element msg) +fadeUi = + Internals.Transition.fadeUi diff --git a/src/Internals/Transition.elm b/src/Internals/Transition.elm new file mode 100644 index 0000000..90705a8 --- /dev/null +++ b/src/Internals/Transition.elm @@ -0,0 +1,162 @@ +module Internals.Transition exposing + ( Transition + , speed, view + , optOut, none, fadeHtml, fadeUi + , Visibility + , visible, invisible + ) + +{-| + +@docs Transition +@docs speed, view +@docs optOut, none, fadeHtml, fadeUi + +@docs Visibility +@docs visible, invisible + +-} + +import Element exposing (Element) +import Html exposing (Html) +import Html.Attributes as Attr + + +type Visibility + = Invisible + | Visible + + +visible : Visibility +visible = + Visible + + +invisible : Visibility +invisible = + Invisible + + +type Transition ui_msg + = OptOut + | None + | Transition (Transition_ ui_msg) + + +type alias Transition_ ui_msg = + { speed : Int + , invisible : View ui_msg + , visible : View ui_msg + } + + +type alias View ui_msg = + { layout : ui_msg -> ui_msg + , page : ui_msg + } + -> ui_msg + + +speed : Transition ui_msg -> Int +speed transition = + case transition of + OptOut -> + 0 + + None -> + 0 + + Transition t -> + t.speed + + +view : + Transition ui_msg + -> Visibility + -> + { layout : ui_msg -> ui_msg + , page : ui_msg + } + -> ui_msg +view transition visibility ({ layout, page } as record) = + case transition of + OptOut -> + layout page + + None -> + layout page + + Transition t -> + case visibility of + Visible -> + t.visible record + + Invisible -> + t.invisible record + + + +-- TRANSITIONS + + +optOut : Transition ui_msg +optOut = + OptOut + + +none : Transition ui_msg +none = + None + + +fadeHtml : Int -> Transition (Html msg) +fadeHtml speed_ = + let + withOpacity : Int -> View (Html msg) + withOpacity opacity { layout, page } = + layout + (Html.div + [ Attr.style "opacity" (String.fromInt opacity) + , Attr.style "transition" <| + String.concat + [ "opacity " + , String.fromInt speed_ + , "ms ease-in-out" + ] + ] + [ page ] + ) + in + Transition <| + { speed = speed_ + , invisible = withOpacity 0 + , visible = withOpacity 1 + } + + +fadeUi : Int -> Transition (Element msg) +fadeUi speed_ = + let + withOpacity : Float -> View (Element msg) + withOpacity opacity { layout, page } = + layout + (Element.el + [ Element.width Element.fill + , Element.height Element.fill + , Element.alpha opacity + , Element.htmlAttribute <| + Attr.style "transition" <| + String.concat + [ "opacity " + , String.fromInt speed_ + , "ms ease-in-out" + ] + ] + page + ) + in + Transition <| + { speed = speed_ + , invisible = withOpacity 0 + , visible = withOpacity 1 + } diff --git a/src/README.md b/src/README.md index dda173a..7222b19 100644 --- a/src/README.md +++ b/src/README.md @@ -1,2 +1,10 @@ # ryannhg/elm-app -> the elm package that makes building `elm-spa` super easy! \ No newline at end of file +> the elm package that makes building `elm-spa` super easy! + + +## local development + +``` +npm run dev +``` +