write docs for new api

This commit is contained in:
Ryan Haskell-Glatz 2019-11-21 18:45:31 -06:00
parent 89e3b99966
commit d54a2711b1
21 changed files with 3336 additions and 153 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
.DS_Store .DS_Store
./dist ./dist
elm-stuff elm-stuff
./node_modules node_modules

View File

@ -7,7 +7,9 @@
"exposed-modules": [ "exposed-modules": [
"Spa", "Spa",
"Spa.Page", "Spa.Page",
"Spa.Types" "Spa.Types",
"Spa.Transition",
"Spa.Path"
], ],
"elm-version": "0.19.0 <= v < 0.20.0", "elm-version": "0.19.0 <= v < 0.20.0",
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
module Components.Button exposing (view) module Components.Button exposing (view)
import Components.Styles as Styles import Utils.Styles as Styles
import Element exposing (..) import Element exposing (..)
import Element.Background as Background import Element.Background as Background
import Element.Border as Border import Element.Border as Border

View File

@ -1,6 +1,6 @@
module Components.Hero exposing (Action(..), view) module Components.Hero exposing (Action(..), view)
import Components.Styles as Styles import Utils.Styles as Styles
import Element exposing (..) import Element exposing (..)
import Element.Input as Input import Element.Input as Input

View File

@ -1,6 +1,6 @@
module Components.Section exposing (view) module Components.Section exposing (view)
import Components.Styles as Styles import Utils.Styles as Styles
import Element exposing (..) import Element exposing (..)
import Html.Attributes as Attr import Html.Attributes as Attr
import Markdown import Markdown

View File

@ -1,7 +1,7 @@
module Layout exposing (view) module Layout exposing (view)
import Components.Button import Components.Button
import Components.Styles as Styles import Utils.Styles as Styles
import Element exposing (..) import Element exposing (..)
import Element.Background as Background import Element.Background as Background
import Element.Border as Border import Element.Border as Border
@ -48,7 +48,7 @@ viewNavbar user_ =
, Font.color Styles.colors.coral , Font.color Styles.colors.coral
, Styles.transition , Styles.transition
{ property = "opacity" { property = "opacity"
, speed = 150 , duration = 150
} }
, mouseOver [ alpha 0.6 ] , mouseOver [ alpha 0.6 ]
] ]

View File

@ -1,6 +1,6 @@
module Layouts.Docs exposing (view) module Layouts.Docs exposing (view)
import Components.Styles as Styles import Utils.Styles as Styles
import Element exposing (..) import Element exposing (..)
import Element.Font as Font import Element.Font as Font
import Generated.Routes as Routes exposing (Route, routes) import Generated.Routes as Routes exposing (Route, routes)

View File

@ -1,6 +1,6 @@
module Layouts.Guide exposing (view) module Layouts.Guide exposing (view)
import Components.Styles as Styles import Utils.Styles as Styles
import Element exposing (..) import Element exposing (..)
import Utils.Spa as Spa import Utils.Spa as Spa

View File

@ -2,7 +2,7 @@ module Pages.SignIn exposing (Model, Msg, page)
import Spa.Page import Spa.Page
import Components.Button import Components.Button
import Components.Styles as Styles import Utils.Styles as Styles
import Element exposing (..) import Element exposing (..)
import Element.Border as Border import Element.Border as Border
import Element.Font as Font import Element.Font as Font

View File

@ -3,7 +3,7 @@ module Pages.Top exposing (Model, Msg, page)
import Spa.Page import Spa.Page
import Components.Hero import Components.Hero
import Components.Section import Components.Section
import Components.Styles as Styles import Utils.Styles as Styles
import Element exposing (..) import Element exposing (..)
import Generated.Params as Params import Generated.Params as Params
import Html.Attributes as Attr import Html.Attributes as Attr

View File

@ -1,29 +1,17 @@
module Transitions exposing (transitions) module Transitions exposing (transitions)
import Components.Styles as Styles import Utils.Styles as Styles
import Element exposing (..) import Element exposing (..)
import Generated.Docs.Pages import Generated.Docs.Pages as Docs
import Layout
import Layouts.Docs
import Layouts.Guide
import Spa.Path exposing (Path)
import Spa.Transition as Transition exposing (Transition) import Spa.Transition as Transition exposing (Transition)
transitions : transitions : Transition.Transitions (Element msg)
{ layout : Transition (Element msg)
, page : Transition (Element msg)
, pages :
List
{ path : Path
, transition : Transition (Element msg)
}
}
transitions = transitions =
{ layout = Transition.fadeUi 300 { layout = Transition.fadeUi 300
, page = Transition.fadeUi 300 , page = Transition.fadeUi 300
, pages = , pages =
[ { path = Generated.Docs.Pages.path [ { path = Docs.path
, transition = batmanNewspaper 600 , transition = batmanNewspaper 600
} }
] ]
@ -35,9 +23,9 @@ transitions =
batmanNewspaper : Int -> Transition (Element msg) batmanNewspaper : Int -> Transition (Element msg)
batmanNewspaper speed = batmanNewspaper duration =
Transition.custom Transition.custom
{ speed = speed { duration = duration
, invisible = , invisible =
\page -> \page ->
el el
@ -47,7 +35,7 @@ batmanNewspaper speed =
, scale 0 , scale 0
, Styles.transition , Styles.transition
{ property = "all" { property = "all"
, speed = speed , duration = duration
} }
] ]
page page
@ -58,7 +46,7 @@ batmanNewspaper speed =
, width fill , width fill
, Styles.transition , Styles.transition
{ property = "all" { property = "all"
, speed = speed , duration = duration
} }
] ]
page page

View File

@ -10,11 +10,11 @@ module Utils.Spa exposing
, recipe , recipe
) )
import Spa.Page
import Spa.Types
import Element exposing (Element) import Element exposing (Element)
import Generated.Routes as Routes exposing (Route) import Generated.Routes as Routes exposing (Route)
import Global import Global
import Spa.Page
import Spa.Types
type alias Page params model msg layoutModel layoutMsg appMsg = type alias Page params model msg layoutModel layoutMsg appMsg =
@ -37,14 +37,6 @@ type alias Bundle msg appMsg =
Spa.Types.Bundle Route msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg) Spa.Types.Bundle Route msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg)
type alias Layout params model msg appMsg =
Spa.Types.Layout Route params model msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg)
type alias Upgrade params model msg layoutModel layoutMsg appMsg =
Spa.Types.Upgrade Route params model msg (Element msg) layoutModel layoutMsg (Element layoutMsg) Global.Model Global.Msg appMsg (Element appMsg)
type alias LayoutContext msg = type alias LayoutContext msg =
Spa.Types.LayoutContext Route msg (Element msg) Global.Model Global.Msg Spa.Types.LayoutContext Route msg (Element msg) Global.Model Global.Msg
@ -53,6 +45,10 @@ type alias PageContext =
Spa.Types.PageContext Route Global.Model Spa.Types.PageContext Route Global.Model
type alias Layout params model msg appMsg =
Spa.Types.Layout Route params model msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg)
layout : layout :
Layout params model msg appMsg Layout params model msg appMsg
-> Page params model msg layoutModel layoutMsg appMsg -> Page params model msg layoutModel layoutMsg appMsg
@ -60,6 +56,10 @@ layout =
Spa.Page.layout Element.map Spa.Page.layout Element.map
type alias Upgrade params model msg layoutModel layoutMsg appMsg =
Spa.Types.Upgrade Route params model msg (Element msg) layoutModel layoutMsg (Element layoutMsg) Global.Model Global.Msg appMsg (Element appMsg)
recipe : recipe :
Upgrade params model msg layoutModel layoutMsg appMsg Upgrade params model msg layoutModel layoutMsg appMsg
-> Recipe params model msg layoutModel layoutMsg appMsg -> Recipe params model msg layoutModel layoutMsg appMsg

View File

@ -1,4 +1,4 @@
module Components.Styles exposing module Utils.Styles exposing
( button ( button
, colors , colors
, fonts , fonts
@ -39,7 +39,7 @@ link =
, Font.color colors.coral , Font.color colors.coral
, transition , transition
{ property = "opacity" { property = "opacity"
, speed = 150 , duration = 150
} }
, mouseOver , mouseOver
[ alpha 0.6 [ alpha 0.6
@ -59,7 +59,7 @@ button =
, pointer , pointer
, transition , transition
{ property = "all" { property = "all"
, speed = 150 , duration = 150
} }
, mouseOver , mouseOver
[ Font.color colors.white [ Font.color colors.white
@ -88,14 +88,14 @@ h3 =
transition : transition :
{ property : String { property : String
, speed : Int , duration : Int
} }
-> Attribute msg -> Attribute msg
transition { property, speed } = transition { property, duration } =
Element.htmlAttribute Element.htmlAttribute
(Attr.style (Attr.style
"transition" "transition"
(property ++ " " ++ String.fromInt speed ++ "ms ease-in-out") (property ++ " " ++ String.fromInt duration ++ "ms ease-in-out")
) )

2893
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,22 @@
{ {
"name": "elm-spa", "name": "elm-spa",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "a package for building single-page applications!",
"main": "cli/src/index.js", "main": "cli/src/index.js",
"bin": "./cli/src/index.js", "bin": "./cli/src/index.js",
"scripts": { "scripts": {
"start": "npm link && npm run dev", "start": "npm link && npm run dev",
"build": "(cd cli && npm run build)", "build": "(cd cli && npm run build)",
"dev": "npm run build && npm run example", "dev": "npm run build && npm run example",
"docs": "elm-doc-preview",
"example": "npm run examples:complex", "example": "npm run examples:complex",
"examples:intro": "(cd examples/intro && npm install && npm run dev)", "examples:intro": "(cd examples/intro && npm install && npm run dev)",
"examples:complex": "(cd examples/complex && npm install && npm run dev)" "examples:complex": "(cd examples/complex && npm install && npm run dev)"
}, },
"dependencies": {}, "dependencies": {},
"devDependencies": {}, "devDependencies": {
"elm": "0.19.1-3",
"elm-doc-preview": "3.0.4"
},
"keywords": [] "keywords": []
} }

View File

@ -1,6 +1,6 @@
module Internals.Transition exposing module Internals.Transition exposing
( Transition ( Transition
, speed, view , duration, view
, optOut, none, fadeHtml, fadeUi , optOut, none, fadeHtml, fadeUi
, Visibility , Visibility
, visible, invisible , visible, invisible
@ -10,7 +10,7 @@ module Internals.Transition exposing
{-| {-|
@docs Transition @docs Transition
@docs speed, view, chooseFrom @docs duration, view, chooseFrom
@docs optOut, none, fadeHtml, fadeUi @docs optOut, none, fadeHtml, fadeUi
@docs Visibility @docs Visibility
@ -46,7 +46,7 @@ type Transition ui_msg
type alias Options ui_msg = type alias Options ui_msg =
{ speed : Int { duration : Int
, invisible : View ui_msg , invisible : View ui_msg
, visible : View ui_msg , visible : View ui_msg
} }
@ -57,8 +57,8 @@ type alias View ui_msg =
-> ui_msg -> ui_msg
speed : Transition ui_msg -> Int duration : Transition ui_msg -> Int
speed transition = duration transition =
case transition of case transition of
OptOut -> OptOut ->
0 0
@ -67,7 +67,7 @@ speed transition =
0 0
Transition t -> Transition t ->
t.speed t.duration
view : view :
@ -107,7 +107,7 @@ none =
fadeHtml : Int -> Transition (Html msg) fadeHtml : Int -> Transition (Html msg)
fadeHtml speed_ = fadeHtml duration_ =
let let
withOpacity : Int -> View (Html msg) withOpacity : Int -> View (Html msg)
withOpacity opacity page = withOpacity opacity page =
@ -116,21 +116,21 @@ fadeHtml speed_ =
, Attr.style "transition" <| , Attr.style "transition" <|
String.concat String.concat
[ "opacity " [ "opacity "
, String.fromInt speed_ , String.fromInt duration_
, "ms ease-in-out" , "ms ease-in-out"
] ]
] ]
[ page ] [ page ]
in in
Transition <| Transition <|
{ speed = speed_ { duration = duration_
, invisible = withOpacity 0 , invisible = withOpacity 0
, visible = withOpacity 1 , visible = withOpacity 1
} }
fadeUi : Int -> Transition (Element msg) fadeUi : Int -> Transition (Element msg)
fadeUi speed_ = fadeUi duration_ =
let let
withOpacity : Float -> View (Element msg) withOpacity : Float -> View (Element msg)
withOpacity opacity page = withOpacity opacity page =
@ -142,21 +142,21 @@ fadeUi speed_ =
Attr.style "transition" <| Attr.style "transition" <|
String.concat String.concat
[ "opacity " [ "opacity "
, String.fromInt speed_ , String.fromInt duration_
, "ms ease-in-out" , "ms ease-in-out"
] ]
] ]
page page
in in
Transition <| Transition <|
{ speed = speed_ { duration = duration_
, invisible = withOpacity 0 , invisible = withOpacity 0
, visible = withOpacity 1 , visible = withOpacity 1
} }
custom : custom :
{ speed : Int { duration : Int
, invisible : View ui_msg , invisible : View ui_msg
, visible : View ui_msg , visible : View ui_msg
} }

View File

@ -1,7 +1,6 @@
module Spa exposing module Spa exposing
( Program, create ( Program, create
, usingHtml , usingHtml
, queryParameters
) )
{-| {-|
@ -14,17 +13,21 @@ as the entrypoint to your app.
import Global import Global
import Pages import Pages
import Routes import Routes exposing (routes)
import Spa import Spa
import Transitions
import Utils.Spa
main : Utils.Spa.Program Pages.Model Pages.Msg
main = main =
Spa.create Spa.create
{ ui = Spa.usingHtml { ui = Spa.usingHtml
, routing = , routing =
{ routes = Routes.parsers { routes = Routes.parsers
, toPath = Routes.toPath , toPath = Routes.toPath
, notFound = Routes.routes.notFound , notFound = routes.notFound
} }
, transitions = Transitions.transitions
, global = , global =
{ init = Global.init { init = Global.init
, update = Global.update , update = Global.update
@ -38,7 +41,7 @@ as the entrypoint to your app.
# using elm-ui? # using elm-ui?
If you're a big fan of [mdgriffith/elm-ui](https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/) (or not-so-big-fan of CSS), If you're a big fan of [mdgriffith/elm-ui](https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/) (or a "not-so-big-fan of CSS"),
this package supports using `Element msg` instead of `Html msg` for your pages and components. this package supports using `Element msg` instead of `Html msg` for your pages and components.
Providing `Spa.create` with these `ui` options will do the trick! Providing `Spa.create` with these `ui` options will do the trick!
@ -80,7 +83,7 @@ type alias Program flags globalModel globalMsg layoutModel layoutMsg =
Platform.Program flags (Model flags globalModel layoutModel) (Msg globalMsg layoutMsg) Platform.Program flags (Model flags globalModel layoutModel) (Msg globalMsg layoutMsg)
{-| Pass this in when calling `Spa.create` {-| If you're just using `elm/html`, you can pass this into `Spa.create`
main = main =
Spa.create Spa.create
@ -104,10 +107,11 @@ usingHtml =
{-| Creates a new `Program` given some one-time configuration: {-| Creates a new `Program` given some one-time configuration:
- `ui` - How do we convert the view to `Html msg`? - `ui` - How do we convert our views into `Html msg`?
- `routing` - What are the app's routes? - `routing` - What are the app's routes?
- `global` - How do we manage shared state between pages? - `transitions` - How should we transition between routes?
- `page` - What pages do we have available? - `global` - How do we share state between pages?
- `page` - What page should we render?
-} -}
create : create :
@ -286,7 +290,7 @@ init config flags url key =
[ Cmd.map Page pageCmd [ Cmd.map Page pageCmd
, Cmd.map Global pageGlobalCmd , Cmd.map Global pageGlobalCmd
, Cmd.map Global globalCmd , Cmd.map Global globalCmd
, Utils.delay (Transition.speed config.routing.transition) FadeInLayout , Utils.delay (Transition.duration config.routing.transition) FadeInLayout
, cmd , cmd
] ]
) )
@ -383,7 +387,7 @@ update config msg model =
ChangedUrl url -> ChangedUrl url ->
let let
( path, speed ) = ( path, duration ) =
chooseFrom chooseFrom
{ transitions = config.routing.transitions { transitions = config.routing.transitions
, from = model.url , from = model.url
@ -391,7 +395,7 @@ update config msg model =
} }
|> Just |> Just
|> Maybe.withDefault (List.head config.routing.transitions) |> Maybe.withDefault (List.head config.routing.transitions)
|> Maybe.map (\item -> ( item.path, Transition.speed item.transition )) |> Maybe.map (\item -> ( item.path, Transition.duration item.transition ))
|> Maybe.withDefault ( [], 0 ) |> Maybe.withDefault ( [], 0 )
in in
( { model ( { model
@ -404,7 +408,7 @@ update config msg model =
} }
, Cmd.batch , Cmd.batch
[ Utils.delay [ Utils.delay
speed duration
(FadeInPage url) (FadeInPage url)
] ]
) )

View File

@ -8,26 +8,34 @@ module Spa.Page exposing
, keep , keep
) )
{-| Each page can be as simple or complex as you need: {-|
1. [Static](#static) - a page without state
2. [Sandbox](#sandbox) - a page without side-effects
3. [Element](#element) - a page _with_ side-effects
4. [Component](#component) - a page that can change the global state
## what's that `always` for? ## Pick the simplest page for the job!
You may notice the examples below use `always`. This is to **opt-out** each 1. [`static`](#static) - a page without state
function from reading the global model.
If you need access to `Global.Model` in your `title`, `init`, `update`, `view`, or 2. [`sandbox`](#sandbox) - a page without side-effects
`subscriptions` functions, just remove the always.
**It is recommended to include this to keep your pages as simple as possible!** 3. [`element`](#element) - a page _with_ side-effects
4. [`component`](#component) - a page that can change the global state
### **heads up:** `always` incoming!
You may notice the examples below use the function `always`.
Page.static
{ title = always "Hello"
, view = always view
}
This is to **opt-out** each function from accessing data like [`PageContext`](./Spa-Types#PageContext)
If you decide you need access to the `Route`, query parameters, or `Global.Model`:
Remove the `always` from `title`, `init`, `update`, `view`, or
`subscriptions` functions.
# static # static
@ -50,13 +58,12 @@ If you need access to `Global.Model` in your `title`, `init`, `update`, `view`,
@docs component, send @docs component, send
# composing pages together # manually composing pages?
The rest of this module contains types and functions that The rest of this module contains types and functions that
can be generated with the [cli companion tool](https://github.com/ryannhg/elm-spa/tree/master/cli) are automatically generated with the [CLI companion tool](https://github.com/ryannhg/elm-spa/tree/master/cli)!
If you're typing this stuff manually, you might need to know what If you'd rather type this stuff manually, these docs are for you!
these are for!
## layout ## layout
@ -69,12 +76,23 @@ these are for!
@docs recipe @docs recipe
## what's a "bundle"? ## wait... what's a "bundle"?
We can "bundle" the `view` and `subscriptions` functions together, We can "bundle" the `title`,`view`, and `subscriptions` functions together,
because they both only need the current `model`. because they only need access to the current `model`.
So _instead_ of typing out these: So _instead_ of typing out all this:
title bigModel =
case bigModel of
FooModel model ->
foo.title model
BarModel model ->
bar.title model
BazModel model ->
baz.title model
view bigModel = view bigModel =
case bigModel of case bigModel of
@ -98,7 +116,7 @@ So _instead_ of typing out these:
BazModel model -> BazModel model ->
baz.subscriptions model baz.subscriptions model
You only need **one** case expression: (woohoo, less boilerplate!) You only create **one** case expression: (woohoo, less typing!)
bundle bigModel = bundle bigModel =
case bigModel of case bigModel of
@ -133,9 +151,9 @@ type alias Page route pageParams pageModel pageMsg ui_pageMsg layoutModel layout
{-| Implementing the `init`, `update` and `bundle` functions is much easier {-| Implementing the `init`, `update` and `bundle` functions is much easier
when you turn a `Page` type into `Recipe`. when you turn a `Page` type into a `Recipe`.
A `Recipe` contains a record waiting for page specific data. A `Recipe` is just an Elm record waiting for its page specific data.
- `init`: just needs a `route` - `init`: just needs a `route`
@ -172,8 +190,8 @@ recipe =
Internals.Page.upgrade Internals.Page.upgrade
{-| In the event that our `case` expression in `update` receives a `msg` that doesn't {-| If the `update` function receives a `msg` that doesn't
match up with it's `model`, we use `keep` to leave the page as-is. match up its `model`, we use `keep` to leave the page as-is.
update : Msg -> Model -> Spa.Update Model Msg update : Msg -> Model -> Spa.Update Model Msg
update bigMsg bigModel = update bigMsg bigModel =
@ -427,8 +445,8 @@ element page =
, init = always init , init = always init
, update = always update , update = always update
, subscriptions = always subscriptions , subscriptions = always subscriptions
-- no always, so `view` gets `Global.Model` , view = view -- no always used here, so view
, view = view -- has access to `PageContext`
} }
title : String title : String
@ -447,11 +465,14 @@ element page =
subscriptions model = subscriptions model =
-- ... -- ...
view : Global.Model -> Model -> Html Msg view : Spa.PageContext -> Model -> Html Msg
view global model = view { global } model =
case global.user of case global.user of
SignedIn _ -> viewSignOutForm SignedIn user ->
SignedOut -> viewSignInForm viewSignOutForm user model
SignedOut ->
viewSignInForm model
-} -}
component : component :
@ -492,7 +513,7 @@ component page =
) )
{-| Useful for sending `Global.Msg` from a component. {-| A utility for sending `Global.Msg` commands from your `Page.component`
init : Params.SignIn -> ( Model, Cmd Msg, Cmd Global.Msg ) init : Params.SignIn -> ( Model, Cmd Msg, Cmd Global.Msg )
init params = init params =

View File

@ -1,21 +1,73 @@
module Spa.Path exposing module Spa.Path exposing
( Path ( Path
, dynamic , static, dynamic
, static
) )
{-|
## specify transitions for different routes!
If you're using the [CLI companion tool](https://github.com/ryannhg/elm-spa/tree/master/cli),
these are **automatically generated**.
If you're doing things by hand, this documentation might be helpful!
@docs Path
@docs static, dynamic
-}
import Internals.Path as Internals import Internals.Path as Internals
{-| a `List` of path segments that you use with `Spa.Transition`
transitions : Spa.Transitions (Element msg)
transitions =
{ layout = Transition.none
, page = Transition.none
, pages =
[ -- applies fade to all pages under `/guide/*`
{ path = [ static "guide" ]
, transition = Transition.fadeUi 300
}
]
}
-}
type alias Path = type alias Path =
Internals.Path Internals.Path
{-| A static segment of a path.
[ static "docs" ]
-- /docs
[ static "docs", static "intro" ]
-- /docs/intro
-}
static : String -> Internals.Piece static : String -> Internals.Piece
static = static =
Internals.static Internals.static
{-| A dynamic segment of a path.
[ static "docs", dynamic ]
-- /docs/welcome
-- /docs/hello
-- /docs/hooray
[ static "docs", dynamic, static "intro" ]
-- /docs/welcome/intro
-- /docs/hello/intro
-- /docs/hooray/intro
-}
dynamic : Internals.Piece dynamic : Internals.Piece
dynamic = dynamic =
Internals.dynamic Internals.dynamic

View File

@ -1,20 +1,50 @@
module Spa.Transition exposing module Spa.Transition exposing
( Transition ( Transition
, none, fadeHtml, fadeUi, custom , none, fadeHtml, fadeUi
, custom
) )
{-| {-|
## Create transitions from page to page!
A huge benefit to doing client-side rendering is the ability to
seamlessly navigate from one page to another!
This package is designed to make creating page transitions a breeze!
@docs Transition @docs Transition
@docs none, fadeHtml, fadeUi, custom
# use one of these transitions
@docs none, fadeHtml, fadeUi
# ot roll your own
@docs custom
-} -}
import Element exposing (Element) import Element exposing (Element)
import Html exposing (Html) import Html exposing (Html)
import Internals.Path exposing (Path)
import Internals.Transition import Internals.Transition
{-| Describes how to move from one page to another.
transition : Transition (Html msg)
transition =
Transition.none
anotherTransition : Transition (Element msg)
anotherTransition =
Transition.fadeUi 300
-}
type alias Transition ui_msg = type alias Transition ui_msg =
Internals.Transition.Transition ui_msg Internals.Transition.Transition ui_msg
@ -23,23 +53,110 @@ type alias Transition ui_msg =
-- TRANSITIONS -- TRANSITIONS
{-| Don't transition from one page to another
transitions : Transitions (Html msg)
transitions =
{ layout = Transition.none -- page loads instantly
, page = Transition.fadeHtml 300
, pages = []
}
-}
none : Transition ui_msg none : Transition ui_msg
none = none =
Internals.Transition.none Internals.Transition.none
{-| Fade one page out and another one in. (For use with `elm/html`)
Animation duration is represented in **milliseconds**
transitions : Spa.Types.Transitions (Html msg)
transitions =
{ layout = Transition.none
, page = Transition.fadeHtml 300 -- 300 milliseconds
, pages = []
}
-}
fadeHtml : Int -> Transition (Html msg) fadeHtml : Int -> Transition (Html msg)
fadeHtml = fadeHtml =
Internals.Transition.fadeHtml Internals.Transition.fadeHtml
{-| Fade one page out and another one in. (For use with `mdgriffith/elm-ui`)
Animation duration is represented in **milliseconds**
transitions : Spa.Types.Transitions (Element msg)
transitions =
{ layout = Transition.none
, page = Transition.fadeUi 300 -- 300 milliseconds
, pages = []
}
-}
fadeUi : Int -> Transition (Element msg) fadeUi : Int -> Transition (Element msg)
fadeUi = fadeUi =
Internals.Transition.fadeUi Internals.Transition.fadeUi
{-| Create your own custom transition!
Just provide three things:
- How long (in milliseconds) the transition lasts.
- What the page looks like when invisible.
- What the page looks like when **visible**.
```
batmanNewspaper : Int -> Transition (Element msg)
batmanNewspaper duration =
Transition.custom
{ duration = duration
, invisible =
\page ->
el
[ alpha 0
, width fill
, rotate (4 * pi)
, scale 0
, Styles.transition
{ property = "all"
, duration = duration
}
]
page
, visible =
\page ->
el
[ alpha 1
, width fill
, Styles.transition
{ property = "all"
, duration = duration
}
]
page
}
--
-- using it later on
--
transitions : Spa.Types.Transitions (Element msg)
transitions =
{ layout = batmanNewspaper 500 -- 🦇
, page = Transition.none
, pages = []
}
```
-}
custom : custom :
{ speed : Int { duration : Int
, invisible : View ui_msg , invisible : View ui_msg
, visible : View ui_msg , visible : View ui_msg
} }

View File

@ -5,24 +5,25 @@ module Spa.Types exposing
, Update , Update
, Bundle , Bundle
, Layout, Upgrade , Layout, Upgrade
, Transitions
, LayoutContext, PageContext , LayoutContext, PageContext
) )
{-| {-|
## types so spooky, they got their own module! 👻 ## types so spooky, they got their own module!
This module is all about exposing the types that `ryannhg/elm-app` uses This module is all about exposing the types that `ryannhg/elm-app` uses
under the hood. under the hood.
At a glance, there are a **lot of generic types**. You might notice that there are a **lot of generic types**.
In practice, we can handle this with a single In practice, we can avoid the messy types with a single
[`Utils/Spa.elm`](https://github.com/ryannhg/elm-spa/blob/master/example/src/Utils/Spa.elm) file that [`Utils/Spa.elm`](https://github.com/ryannhg/elm-spa/blob/master/example/src/Utils/Spa.elm) file that
makes your types easier to understand! makes your types easier to understand!
`elm-spa init` generates that file for you, but I've added examples below if you're `elm-spa init` will generate that file for you, but I've added examples below if you're
doing things by hand. doing things by hand.
@ -55,9 +56,22 @@ doing things by hand.
@docs Layout, Upgrade @docs Layout, Upgrade
# transitions
@docs Transitions
# context
@docs LayoutContext, PageContext
-} -}
import Dict exposing (Dict)
import Internals.Page as Page import Internals.Page as Page
import Internals.Path exposing (Path)
import Internals.Transition exposing (Transition)
{-| {-|
@ -73,7 +87,7 @@ import Internals.Page as Page
import Element exposing (Element) import Element exposing (Element)
type alias Page params model msg layoutModel layoutMsg appMsg = type alias Page params model msg layoutModel layoutMsg appMsg =
Spa.Types.Page params model msg (Element msg) layoutModel layoutMsg (Element layoutMsg) Global.Model Global.Msg appMsg (Element appMsg) Spa.Types.Page Route params model msg (Element msg) layoutModel layoutMsg (Element layoutMsg) Global.Model Global.Msg appMsg (Element appMsg)
-- if using elm/html -- if using elm/html
@ -81,7 +95,7 @@ import Internals.Page as Page
import Html exposing (Html) import Html exposing (Html)
type alias Page params model msg layoutModel layoutMsg appMsg = type alias Page params model msg layoutModel layoutMsg appMsg =
Spa.Types.Page params model msg (Html msg) layoutModel layoutMsg (Html layoutMsg) Global.Model Global.Msg appMsg (Html appMsg) Spa.Types.Page Route params model msg (Html msg) layoutModel layoutMsg (Html layoutMsg) Global.Model Global.Msg appMsg (Html appMsg)
## using your alias ## using your alias
@ -112,7 +126,7 @@ type alias Page route params pageModel pageMsg ui_pageMsg layoutModel layoutMsg
import Element exposing (Element) import Element exposing (Element)
type alias Recipe params model msg layoutModel layoutMsg appMsg = type alias Recipe params model msg layoutModel layoutMsg appMsg =
Spa.Types.Recipe params model msg layoutModel layoutMsg (Element layoutMsg) Global.Model Global.Msg appMsg (Element appMsg) Spa.Types.Recipe Route params model msg layoutModel layoutMsg (Element layoutMsg) Global.Model Global.Msg appMsg (Element appMsg)
-- if using elm/html -- if using elm/html
@ -120,7 +134,7 @@ type alias Page route params pageModel pageMsg ui_pageMsg layoutModel layoutMsg
import Html exposing (Html) import Html exposing (Html)
type alias Recipe params model msg layoutModel layoutMsg appMsg = type alias Recipe params model msg layoutModel layoutMsg appMsg =
Spa.Types.Recipe params model msg layoutModel layoutMsg (Html layoutMsg) Global.Model Global.Msg appMsg (Html appMsg) Spa.Types.Recipe Route params model msg layoutModel layoutMsg (Html layoutMsg) Global.Model Global.Msg appMsg (Html appMsg)
## using your alias ## using your alias
@ -148,7 +162,7 @@ type alias Recipe route params pageModel pageMsg layoutModel layoutMsg ui_layout
**`src/Utils/Spa.elm`** **`src/Utils/Spa.elm`**
type alias Init model msg = type alias Init model msg =
Spa.Types.Init model msg Global.Model Global.Msg Spa.Types.Init Route model msg Global.Model Global.Msg
## using your alias ## using your alias
@ -175,7 +189,7 @@ type alias Init route layoutModel layoutMsg globalModel globalMsg =
**`src/Utils/Spa.elm`** **`src/Utils/Spa.elm`**
type alias Update model msg = type alias Update model msg =
Spa.Types.Update model msg Global.Model Global.Msg Spa.Types.Update Route model msg Global.Model Global.Msg
## using your alias ## using your alias
@ -207,7 +221,7 @@ type alias Update route layoutModel layoutMsg globalModel globalMsg =
import Element exposing (Element) import Element exposing (Element)
type alias Bundle msg appMsg = type alias Bundle msg appMsg =
Spa.Types.Bundle msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg) Spa.Types.Bundle Route msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg)
-- if using elm/html -- if using elm/html
@ -215,7 +229,7 @@ type alias Update route layoutModel layoutMsg globalModel globalMsg =
import Html exposing (Html) import Html exposing (Html)
type alias Bundle msg appMsg = type alias Bundle msg appMsg =
Spa.Types.Bundle msg (Html msg) Global.Model Global.Msg appMsg (Html appMsg) Spa.Types.Bundle Route msg (Html msg) Global.Model Global.Msg appMsg (Html appMsg)
## using your alias ## using your alias
@ -246,44 +260,135 @@ type alias Bundle route layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg
import Spa.Types import Spa.Types
import Element exposing (Element) import Element exposing (Element)
type alias Bundle msg appMsg = type alias Layout params model msg appMsg =
Spa.Types.Bundle msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg) Spa.Types.Layout Route params model msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg)
-- if using elm/html -- if using elm/html
import Spa.Types import Spa.Types
import Html exposing (Html) import Html exposing (Html)
type alias Bundle msg appMsg = type alias Layout params model msg appMsg =
Spa.Types.Bundle msg (Html msg) Global.Model Global.Msg appMsg (Html appMsg) Spa.Types.Layout Route params model msg (Html msg) Global.Model Global.Msg appMsg (Html appMsg)
## using your alias ## using your alias
**`.elm-spa/Generated/Pages.elm`** **`src/Utils/Spa.elm`**
import Utils.Spa as Spa layout :
Layout params model msg appMsg
bundle : Model -> Spa.Bundle Msg msg -> Page params model msg layoutModel layoutMsg appMsg
bundle model_ = layout =
case model_ of Spa.Page.layout Element.map
-- ...
-} -}
type alias Layout route pageParams pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg = type alias Layout route pageParams pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg =
Page.Layout route pageParams pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg Page.Layout route pageParams pageModel pageMsg ui_pageMsg globalModel globalMsg msg ui_msg
{-| TODO: PageContext docs {-| Describes how to transition between layouts and pages.
transitions : Transitions (Html msg)
transitions =
{ layout = Transition.none -- page loads instantly
, page = Transition.fadeHtml 300
, pages = []
}
-}
type alias Transitions ui_msg =
{ layout : Transition ui_msg
, page : Transition ui_msg
, pages :
List
{ path : Path
, transition : Transition ui_msg
}
}
{-| This is what your `src/Pages/*.elm` files can access!
## creating your alias
**`src/Utils/Spa.elm`**
type alias PageContext =
Spa.Types.PageContext Route Global.Model
## using your alias
**`src/Pages/Top.elm`**
import Utils.Spa as Spa
page =
Page.static
{ title = always "Homepage"
, view = view -- leaving off always here!
}
view : PageContext -> Html Msg
view context =
case context.global.user of
SignedIn user ->
viewUser user
SignedOut ->
text "Who dis?"
-} -}
type alias PageContext route globalModel = type alias PageContext route globalModel =
Page.PageContext route globalModel { global : globalModel
, route : route
, queryParameters : Dict String String
}
{-| TODO: LayoutContext docs {-| This is what your `src/Layouts/*.elm` files can access!
## creating your alias
**`src/Utils/Spa.elm`**
type alias LayoutContext msg =
Spa.Types.LayoutContext Route msg (Element msg) Global.Model Global.Msg
## using your alias
**`src/Layout.elm`**
import Utils.Spa as Spa
view : Spa.LayoutContext msg -> Html msg
view { page, fromGlobalMsg, global } =
div [ class "app" ]
[ Html.map fromGlobalMsg (viewNavbar global)
, page
, viewFooter
]
viewNavbar : Global.Model -> Html Global.Msg
viewNavbar =
-- ...
viewFooter : Html msg
viewFooter =
-- ...
-} -}
type alias LayoutContext route msg ui_msg globalModel globalMsg = type alias LayoutContext route msg ui_msg globalModel globalMsg =
Page.LayoutContext route msg ui_msg globalModel globalMsg { page : ui_msg
, route : route
, global : globalModel
, fromGlobalMsg : globalMsg -> msg
}
{-| {-|
@ -298,28 +403,27 @@ type alias LayoutContext route msg ui_msg globalModel globalMsg =
import Spa.Types import Spa.Types
import Element exposing (Element) import Element exposing (Element)
type alias Bundle msg appMsg = type alias Upgrade params model msg layoutModel layoutMsg appMsg =
Spa.Types.Bundle msg (Element msg) Global.Model Global.Msg appMsg (Element appMsg) Spa.Types.Upgrade Route params model msg (Element msg) layoutModel layoutMsg (Element layoutMsg) Global.Model Global.Msg appMsg (Element appMsg)
-- if using elm/html -- if using elm/html
import Spa.Types import Spa.Types
import Html exposing (Html) import Html exposing (Html)
type alias Bundle msg appMsg = type alias Upgrade params model msg layoutModel layoutMsg appMsg =
Spa.Types.Bundle msg (Html msg) Global.Model Global.Msg appMsg (Html appMsg) Spa.Types.Upgrade Route params model msg (Html msg) layoutModel layoutMsg (Html layoutMsg) Global.Model Global.Msg appMsg (Html appMsg)
## using your alias ## using your alias
**`.elm-spa/Generated/Pages.elm`** **`src/Utils/Spa.elm`**
import Utils.Spa as Spa recipe :
Upgrade params model msg layoutModel layoutMsg appMsg
bundle : Model -> Spa.Bundle Msg msg -> Recipe params model msg layoutModel layoutMsg appMsg
bundle model_ = recipe =
case model_ of Spa.Page.recipe Element.map
-- ...
-} -}
type alias Upgrade route pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg = type alias Upgrade route pageParams pageModel pageMsg ui_pageMsg layoutModel layoutMsg ui_layoutMsg globalModel globalMsg msg ui_msg =