mirror of
https://github.com/ryannhg/elm-spa.git
synced 2024-11-25 14:39:52 +03:00
thats the magic of macys
This commit is contained in:
parent
a6e5229c82
commit
7f5f61e957
33
elm.json
33
elm.json
@ -1,24 +1,19 @@
|
||||
{
|
||||
"type": "application",
|
||||
"source-directories": [
|
||||
"src"
|
||||
"type": "package",
|
||||
"name": "ryannhg/elm-app",
|
||||
"summary": "an experiment for making single page apps with Elm",
|
||||
"license": "BSD-3-Clause",
|
||||
"version": "0.1.0",
|
||||
"exposed-modules": [
|
||||
"Application",
|
||||
"Application.Page"
|
||||
],
|
||||
"elm-version": "0.19.0",
|
||||
"elm-version": "0.19.0 <= v < 0.20.0",
|
||||
"dependencies": {
|
||||
"direct": {
|
||||
"elm/browser": "1.0.1",
|
||||
"elm/core": "1.0.2",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/url": "1.0.0"
|
||||
},
|
||||
"indirect": {
|
||||
"elm/json": "1.1.3",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.2"
|
||||
}
|
||||
"elm/browser": "1.0.1",
|
||||
"elm/core": "1.0.2",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/url": "1.0.0"
|
||||
},
|
||||
"test-dependencies": {
|
||||
"direct": {},
|
||||
"indirect": {}
|
||||
}
|
||||
"test-dependencies": {}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
<link rel="stylesheet" href="./main.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
79
examples/basic/main.css
Normal file
79
examples/basic/main.css
Normal file
@ -0,0 +1,79 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
|
||||
.app {
|
||||
height: 100%;
|
||||
padding: 2rem 1rem;
|
||||
box-sizing: border-box;
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.navbar__links {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
.navbar__links > *:first-child {
|
||||
font-size: 20px;
|
||||
}
|
||||
.navbar__links > :not(:first-child) {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 0.25rem 0.5rem;
|
||||
border: solid 1px #ccc;
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
border: solid 1px #ccc;
|
||||
padding: 0.5rem 1.5rem;
|
||||
background: #06f;
|
||||
color: white;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
label div {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.layout > * {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
flex: 1 0 auto;
|
||||
padding: 2rem 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding-bottom: 1rem;
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
module App exposing
|
||||
( Model
|
||||
, Msg
|
||||
, bundle
|
||||
, init
|
||||
, subscriptions
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Application.Page as Page exposing (Context)
|
||||
import Browser
|
||||
import Context
|
||||
import Flags exposing (Flags)
|
||||
import Html exposing (Html)
|
||||
@ -15,6 +15,7 @@ import Pages.Counter
|
||||
import Pages.Homepage
|
||||
import Pages.NotFound
|
||||
import Pages.Random
|
||||
import Pages.SignIn
|
||||
import Route exposing (Route)
|
||||
|
||||
|
||||
@ -22,6 +23,7 @@ type Model
|
||||
= HomepageModel ()
|
||||
| CounterModel Pages.Counter.Model
|
||||
| RandomModel Pages.Random.Model
|
||||
| SignInModel Pages.SignIn.Model
|
||||
| NotFoundModel ()
|
||||
|
||||
|
||||
@ -29,18 +31,21 @@ type Msg
|
||||
= HomepageMsg Never
|
||||
| CounterMsg Pages.Counter.Msg
|
||||
| RandomMsg Pages.Random.Msg
|
||||
| SignInMsg Pages.SignIn.Msg
|
||||
| NotFoundMsg Never
|
||||
|
||||
|
||||
pages =
|
||||
{ homepage =
|
||||
Page.static
|
||||
{ view = Pages.Homepage.view
|
||||
{ title = Pages.Homepage.title
|
||||
, view = Pages.Homepage.view
|
||||
, toModel = HomepageModel
|
||||
}
|
||||
, counter =
|
||||
Page.sandbox
|
||||
{ init = Pages.Counter.init
|
||||
{ title = Pages.Counter.title
|
||||
, init = Pages.Counter.init
|
||||
, update = Pages.Counter.update
|
||||
, view = Pages.Counter.view
|
||||
, toModel = CounterModel
|
||||
@ -48,16 +53,28 @@ pages =
|
||||
}
|
||||
, random =
|
||||
Page.element
|
||||
{ init = Pages.Random.init
|
||||
{ title = Pages.Random.title
|
||||
, init = Pages.Random.init
|
||||
, update = Pages.Random.update
|
||||
, subscriptions = Pages.Random.subscriptions
|
||||
, view = Pages.Random.view
|
||||
, toModel = RandomModel
|
||||
, toMsg = RandomMsg
|
||||
}
|
||||
, signIn =
|
||||
Page.page
|
||||
{ title = Pages.SignIn.title
|
||||
, init = Pages.SignIn.init
|
||||
, update = Pages.SignIn.update
|
||||
, subscriptions = Pages.SignIn.subscriptions
|
||||
, view = Pages.SignIn.view
|
||||
, toModel = SignInModel
|
||||
, toMsg = SignInMsg
|
||||
}
|
||||
, notFound =
|
||||
Page.static
|
||||
{ view = Pages.NotFound.view
|
||||
{ title = Pages.NotFound.title
|
||||
, view = Pages.NotFound.view
|
||||
, toModel = NotFoundModel
|
||||
}
|
||||
}
|
||||
@ -70,23 +87,33 @@ init context =
|
||||
case context.route of
|
||||
Route.Homepage ->
|
||||
Page.init
|
||||
{ page = pages.homepage }
|
||||
context
|
||||
{ page = pages.homepage
|
||||
, context = context
|
||||
}
|
||||
|
||||
Route.Counter ->
|
||||
Page.init
|
||||
{ page = pages.counter }
|
||||
context
|
||||
{ page = pages.counter
|
||||
, context = context
|
||||
}
|
||||
|
||||
Route.Random ->
|
||||
Page.init
|
||||
{ page = pages.random }
|
||||
context
|
||||
{ page = pages.random
|
||||
, context = context
|
||||
}
|
||||
|
||||
Route.SignIn ->
|
||||
Page.init
|
||||
{ page = pages.signIn
|
||||
, context = context
|
||||
}
|
||||
|
||||
Route.NotFound ->
|
||||
Page.init
|
||||
{ page = pages.notFound }
|
||||
context
|
||||
{ page = pages.notFound
|
||||
, context = context
|
||||
}
|
||||
|
||||
|
||||
update :
|
||||
@ -101,8 +128,8 @@ update context appMsg appModel =
|
||||
{ page = pages.homepage
|
||||
, msg = msg
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
context
|
||||
|
||||
( HomepageModel _, _ ) ->
|
||||
( appModel
|
||||
@ -115,8 +142,8 @@ update context appMsg appModel =
|
||||
{ page = pages.counter
|
||||
, msg = msg
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
context
|
||||
|
||||
( CounterModel _, _ ) ->
|
||||
( appModel
|
||||
@ -129,8 +156,8 @@ update context appMsg appModel =
|
||||
{ page = pages.random
|
||||
, msg = msg
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
context
|
||||
|
||||
( RandomModel _, _ ) ->
|
||||
( appModel
|
||||
@ -138,13 +165,27 @@ update context appMsg appModel =
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
( SignInModel model, SignInMsg msg ) ->
|
||||
Page.update
|
||||
{ page = pages.signIn
|
||||
, msg = msg
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
|
||||
( SignInModel _, _ ) ->
|
||||
( appModel
|
||||
, Cmd.none
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
( NotFoundModel model, NotFoundMsg msg ) ->
|
||||
Page.update
|
||||
{ page = pages.notFound
|
||||
, msg = msg
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
context
|
||||
|
||||
( NotFoundModel _, _ ) ->
|
||||
( appModel
|
||||
@ -153,71 +194,43 @@ update context appMsg appModel =
|
||||
)
|
||||
|
||||
|
||||
subscriptions :
|
||||
bundle :
|
||||
Context Flags Route Context.Model
|
||||
-> Model
|
||||
-> Sub Msg
|
||||
subscriptions context appModel =
|
||||
-> Page.Bundle Msg
|
||||
bundle context appModel =
|
||||
case appModel of
|
||||
HomepageModel model ->
|
||||
Page.subscriptions
|
||||
Page.bundle
|
||||
{ page = pages.homepage
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
context
|
||||
|
||||
CounterModel model ->
|
||||
Page.subscriptions
|
||||
Page.bundle
|
||||
{ page = pages.counter
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
context
|
||||
|
||||
RandomModel model ->
|
||||
Page.subscriptions
|
||||
Page.bundle
|
||||
{ page = pages.random
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
|
||||
SignInModel model ->
|
||||
Page.bundle
|
||||
{ page = pages.signIn
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
context
|
||||
|
||||
NotFoundModel model ->
|
||||
Page.subscriptions
|
||||
Page.bundle
|
||||
{ page = pages.notFound
|
||||
, model = model
|
||||
, context = context
|
||||
}
|
||||
context
|
||||
|
||||
|
||||
view :
|
||||
Context Flags Route Context.Model
|
||||
-> Model
|
||||
-> Html Msg
|
||||
view context appModel =
|
||||
case appModel of
|
||||
HomepageModel model ->
|
||||
Page.view
|
||||
{ page = pages.homepage
|
||||
, model = model
|
||||
}
|
||||
context
|
||||
|
||||
CounterModel model ->
|
||||
Page.view
|
||||
{ page = pages.counter
|
||||
, model = model
|
||||
}
|
||||
context
|
||||
|
||||
RandomModel model ->
|
||||
Page.view
|
||||
{ page = pages.random
|
||||
, model = model
|
||||
}
|
||||
context
|
||||
|
||||
NotFoundModel model ->
|
||||
Page.view
|
||||
{ page = pages.notFound
|
||||
, model = model
|
||||
}
|
||||
context
|
||||
|
@ -1,26 +1,29 @@
|
||||
module Context exposing
|
||||
( Model
|
||||
, Msg
|
||||
, Msg(..)
|
||||
, init
|
||||
, subscriptions
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Application
|
||||
import Data.User exposing (User)
|
||||
import Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes as Attr
|
||||
import Html.Attributes as Attr exposing (class)
|
||||
import Html.Events as Events
|
||||
import Route exposing (Route)
|
||||
import Utils.Cmd
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ user : Maybe String
|
||||
{ user : Maybe User
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= SignIn String
|
||||
= SignIn (Result String User)
|
||||
| SignOut
|
||||
|
||||
|
||||
@ -31,18 +34,25 @@ init route flags =
|
||||
)
|
||||
|
||||
|
||||
update : Route -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update route msg model =
|
||||
update :
|
||||
Application.Messages Route msg
|
||||
-> Route
|
||||
-> Msg
|
||||
-> Model
|
||||
-> ( Model, Cmd Msg, Cmd msg )
|
||||
update { navigateTo } route msg model =
|
||||
case msg of
|
||||
SignIn user ->
|
||||
SignIn (Ok user) ->
|
||||
( { model | user = Just user }
|
||||
, Cmd.none
|
||||
, navigateTo Route.Homepage
|
||||
)
|
||||
|
||||
SignIn (Err _) ->
|
||||
Utils.Cmd.pure model
|
||||
|
||||
SignOut ->
|
||||
( { model | user = Nothing }
|
||||
, Cmd.none
|
||||
)
|
||||
Utils.Cmd.pure { model | user = Nothing }
|
||||
|
||||
|
||||
view :
|
||||
@ -53,19 +63,17 @@ view :
|
||||
}
|
||||
-> Html msg
|
||||
view { context, route, toMsg, viewPage } =
|
||||
div [ Attr.class "layout" ]
|
||||
div [ class "layout" ]
|
||||
[ Html.map toMsg (viewNavbar route context)
|
||||
, br [] []
|
||||
, viewPage
|
||||
, br [] []
|
||||
, div [ class "container" ] [ viewPage ]
|
||||
, Html.map toMsg (viewFooter context)
|
||||
]
|
||||
|
||||
|
||||
viewNavbar : Route -> Model -> Html Msg
|
||||
viewNavbar currentRoute model =
|
||||
header [ Attr.class "navbar" ]
|
||||
[ ul []
|
||||
header [ class "navbar" ]
|
||||
[ div [ class "navbar__links" ]
|
||||
(List.map
|
||||
(viewLink currentRoute)
|
||||
[ Route.Homepage, Route.Counter, Route.Random ]
|
||||
@ -75,31 +83,53 @@ viewNavbar currentRoute model =
|
||||
button [ Events.onClick SignOut ] [ text <| "Sign out" ]
|
||||
|
||||
Nothing ->
|
||||
button [ Events.onClick (SignIn "Ryan") ] [ text "Sign in" ]
|
||||
a [ Attr.href "/sign-in" ] [ text "Sign in" ]
|
||||
]
|
||||
|
||||
|
||||
viewLink : Route -> Route -> Html msg
|
||||
viewLink currentRoute route =
|
||||
li []
|
||||
[ a
|
||||
[ Attr.href (Route.toPath route)
|
||||
, Attr.style "font-weight"
|
||||
(if route == currentRoute then
|
||||
"bold"
|
||||
a
|
||||
[ class "navbar__link-item"
|
||||
, Attr.href (Route.toPath route)
|
||||
, Attr.style "font-weight"
|
||||
(if route == currentRoute then
|
||||
"bold"
|
||||
|
||||
else
|
||||
"normal"
|
||||
)
|
||||
]
|
||||
[ text (Route.title route) ]
|
||||
else
|
||||
"normal"
|
||||
)
|
||||
]
|
||||
[ text (linkLabel route) ]
|
||||
|
||||
|
||||
linkLabel : Route -> String
|
||||
linkLabel route =
|
||||
case route of
|
||||
Route.Homepage ->
|
||||
"Home"
|
||||
|
||||
Route.Counter ->
|
||||
"Counter"
|
||||
|
||||
Route.SignIn ->
|
||||
"Sign In"
|
||||
|
||||
Route.Random ->
|
||||
"Random"
|
||||
|
||||
Route.NotFound ->
|
||||
"Not found"
|
||||
|
||||
|
||||
viewFooter : Model -> Html Msg
|
||||
viewFooter model =
|
||||
footer [ Attr.class "footer" ]
|
||||
[ model.user |> Maybe.withDefault "Not signed in" |> text
|
||||
[ model.user
|
||||
|> Maybe.map Data.User.username
|
||||
|> Maybe.withDefault "not signed in"
|
||||
|> (++) "Current user: "
|
||||
|> text
|
||||
]
|
||||
|
||||
|
||||
|
28
examples/basic/src/Data/User.elm
Normal file
28
examples/basic/src/Data/User.elm
Normal file
@ -0,0 +1,28 @@
|
||||
module Data.User exposing (User, signIn, username)
|
||||
|
||||
import Utils.Cmd
|
||||
|
||||
|
||||
type User
|
||||
= User String
|
||||
|
||||
|
||||
username : User -> String
|
||||
username (User username_) =
|
||||
username_
|
||||
|
||||
|
||||
signIn :
|
||||
{ username : String
|
||||
, password : String
|
||||
, msg : Result String User -> msg
|
||||
}
|
||||
-> Cmd msg
|
||||
signIn options =
|
||||
(Utils.Cmd.toCmd << options.msg) <|
|
||||
case ( options.username, options.password ) of
|
||||
( _, "password" ) ->
|
||||
Ok (User options.username)
|
||||
|
||||
_ ->
|
||||
Err "Sign in failed."
|
@ -24,9 +24,10 @@ main =
|
||||
, page =
|
||||
{ init = App.init
|
||||
, update = App.update
|
||||
, view = App.view
|
||||
, subscriptions = App.subscriptions
|
||||
, bundle = App.bundle
|
||||
}
|
||||
, route =
|
||||
{ fromUrl = Route.fromUrl
|
||||
, toPath = Route.toPath
|
||||
}
|
||||
, toRoute = Route.fromUrl
|
||||
, title = Route.title
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
module Pages.Counter exposing (Model, Msg, init, update, view)
|
||||
module Pages.Counter exposing
|
||||
( Model
|
||||
, Msg
|
||||
, init
|
||||
, title
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Html exposing (..)
|
||||
import Html.Events as Events
|
||||
@ -14,6 +21,11 @@ type Msg
|
||||
| Decrement
|
||||
|
||||
|
||||
title : Model -> String
|
||||
title model =
|
||||
"Counter: " ++ String.fromInt model.counter ++ " | elm-app"
|
||||
|
||||
|
||||
init : Model
|
||||
init =
|
||||
{ counter = 0
|
||||
@ -33,7 +45,11 @@ update msg model =
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div []
|
||||
[ button [ Events.onClick Decrement ] [ text "-" ]
|
||||
, text (String.fromInt model.counter)
|
||||
, button [ Events.onClick Increment ] [ text "+" ]
|
||||
[ h1 [] [ text "Counter!" ]
|
||||
, p [] [ text "Even the browser tab updates!" ]
|
||||
, div []
|
||||
[ button [ Events.onClick Decrement ] [ text "-" ]
|
||||
, text (String.fromInt model.counter)
|
||||
, button [ Events.onClick Increment ] [ text "+" ]
|
||||
]
|
||||
]
|
||||
|
@ -1,8 +1,19 @@
|
||||
module Pages.Homepage exposing (view)
|
||||
module Pages.Homepage exposing
|
||||
( title
|
||||
, view
|
||||
)
|
||||
|
||||
import Html exposing (Html)
|
||||
import Html exposing (..)
|
||||
|
||||
|
||||
title : String
|
||||
title =
|
||||
"Homepage"
|
||||
|
||||
|
||||
view : Html Never
|
||||
view =
|
||||
Html.text "Homepage!"
|
||||
div []
|
||||
[ h1 [] [ text "Homepage!" ]
|
||||
, p [] [ text "It's boring, but it works!" ]
|
||||
]
|
||||
|
@ -1,8 +1,22 @@
|
||||
module Pages.NotFound exposing (view)
|
||||
module Pages.NotFound exposing
|
||||
( title
|
||||
, view
|
||||
)
|
||||
|
||||
import Html exposing (Html)
|
||||
import Html exposing (..)
|
||||
|
||||
|
||||
title : String
|
||||
title =
|
||||
"Not found."
|
||||
|
||||
|
||||
view : Html Never
|
||||
view =
|
||||
Html.text "Page not found..."
|
||||
div []
|
||||
[ h1 [] [ text "Page not found!" ]
|
||||
, p []
|
||||
[ text "Is this space? Am I in "
|
||||
, em [] [ text "space?" ]
|
||||
]
|
||||
]
|
||||
|
@ -3,6 +3,7 @@ module Pages.Random exposing
|
||||
, Msg
|
||||
, init
|
||||
, subscriptions
|
||||
, title
|
||||
, update
|
||||
, view
|
||||
)
|
||||
@ -23,6 +24,11 @@ type Msg
|
||||
| GotOutcome Int
|
||||
|
||||
|
||||
title : Model -> String
|
||||
title model =
|
||||
"Random | elm-app"
|
||||
|
||||
|
||||
init : Flags -> ( Model, Cmd Msg )
|
||||
init _ =
|
||||
( { roll = Nothing }
|
||||
@ -52,12 +58,16 @@ update msg model =
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div []
|
||||
[ button [ Events.onClick Roll ] [ text "Roll" ]
|
||||
, p []
|
||||
[ model.roll
|
||||
|> Maybe.map String.fromInt
|
||||
|> Maybe.withDefault "Click the button!"
|
||||
|> text
|
||||
[ h1 [] [ text "Random!" ]
|
||||
, p [] [ text "Did somebody say 'random numbers pls'?" ]
|
||||
, div []
|
||||
[ button [ Events.onClick Roll ] [ text "Roll" ]
|
||||
, p []
|
||||
[ model.roll
|
||||
|> Maybe.map String.fromInt
|
||||
|> Maybe.withDefault "Click the button!"
|
||||
|> text
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
136
examples/basic/src/Pages/SignIn.elm
Normal file
136
examples/basic/src/Pages/SignIn.elm
Normal file
@ -0,0 +1,136 @@
|
||||
module Pages.SignIn exposing
|
||||
( Model
|
||||
, Msg
|
||||
, init
|
||||
, subscriptions
|
||||
, title
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Application.Page exposing (Context)
|
||||
import Context
|
||||
import Data.User as User exposing (User)
|
||||
import Flags exposing (Flags)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes as Attr
|
||||
import Html.Events as Events
|
||||
import Route exposing (Route)
|
||||
import Utils.Cmd
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ username : String
|
||||
, password : String
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= Update Field String
|
||||
| AttemptSignIn
|
||||
|
||||
|
||||
type Field
|
||||
= Username
|
||||
| Password
|
||||
|
||||
|
||||
title : Context Flags Route Context.Model -> Model -> String
|
||||
title { context } model =
|
||||
case context.user of
|
||||
Just user ->
|
||||
"Sign out " ++ User.username user ++ " | elm-app"
|
||||
|
||||
Nothing ->
|
||||
"Sign in | elm-app"
|
||||
|
||||
|
||||
init :
|
||||
Context Flags Route Context.Model
|
||||
-> ( Model, Cmd Msg, Cmd Context.Msg )
|
||||
init _ =
|
||||
Utils.Cmd.pure { username = "", password = "" }
|
||||
|
||||
|
||||
update :
|
||||
Context Flags Route Context.Model
|
||||
-> Msg
|
||||
-> Model
|
||||
-> ( Model, Cmd Msg, Cmd Context.Msg )
|
||||
update _ msg model =
|
||||
case msg of
|
||||
Update Username value ->
|
||||
Utils.Cmd.pure { model | username = value }
|
||||
|
||||
Update Password value ->
|
||||
Utils.Cmd.pure { model | password = value }
|
||||
|
||||
AttemptSignIn ->
|
||||
( model
|
||||
, Cmd.none
|
||||
, User.signIn
|
||||
{ username = model.username
|
||||
, password = model.password
|
||||
, msg = Context.SignIn
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
view :
|
||||
Context Flags Route Context.Model
|
||||
-> Model
|
||||
-> Html Msg
|
||||
view _ model =
|
||||
div []
|
||||
[ h1 [] [ text "Sign in" ]
|
||||
, p [] [ text "and update some user state!" ]
|
||||
, Html.form [ Events.onSubmit AttemptSignIn ]
|
||||
[ viewInput
|
||||
{ label = "Username"
|
||||
, fieldType = "text"
|
||||
, value = model.username
|
||||
, onInput = Update Username
|
||||
}
|
||||
, viewInput
|
||||
{ label = "Password"
|
||||
, fieldType = "password"
|
||||
, value = model.password
|
||||
, onInput = Update Password
|
||||
}
|
||||
, p []
|
||||
[ button
|
||||
[ Attr.class "button"
|
||||
, Attr.type_ "submit"
|
||||
]
|
||||
[ text "Sign in"
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
viewInput :
|
||||
{ label : String
|
||||
, fieldType : String
|
||||
, value : String
|
||||
, onInput : String -> msg
|
||||
}
|
||||
-> Html msg
|
||||
viewInput options =
|
||||
label []
|
||||
[ div [] [ text options.label ]
|
||||
, input
|
||||
[ Attr.value options.value
|
||||
, Attr.type_ options.fieldType
|
||||
, Events.onInput options.onInput
|
||||
]
|
||||
[]
|
||||
]
|
||||
|
||||
|
||||
subscriptions :
|
||||
Context Flags Route Context.Model
|
||||
-> Model
|
||||
-> Sub Msg
|
||||
subscriptions _ model =
|
||||
Sub.none
|
@ -1,4 +1,4 @@
|
||||
module Route exposing (Route(..), fromUrl, title, toPath)
|
||||
module Route exposing (Route(..), fromUrl, toPath)
|
||||
|
||||
import Url exposing (Url)
|
||||
import Url.Parser as Parser exposing (Parser)
|
||||
@ -6,6 +6,7 @@ import Url.Parser as Parser exposing (Parser)
|
||||
|
||||
type Route
|
||||
= Homepage
|
||||
| SignIn
|
||||
| Counter
|
||||
| Random
|
||||
| NotFound
|
||||
@ -13,46 +14,31 @@ type Route
|
||||
|
||||
fromUrl : Url -> Route
|
||||
fromUrl =
|
||||
Parser.parse router >> Maybe.withDefault NotFound
|
||||
|
||||
|
||||
router : Parser (Route -> Route) Route
|
||||
router =
|
||||
Parser.oneOf
|
||||
[ Parser.map Homepage Parser.top
|
||||
, Parser.map Counter (Parser.s "counter")
|
||||
, Parser.map Random (Parser.s "random")
|
||||
]
|
||||
Parser.parse
|
||||
(Parser.oneOf
|
||||
[ Parser.map Homepage Parser.top
|
||||
, Parser.map SignIn (Parser.s "sign-in")
|
||||
, Parser.map Counter (Parser.s "counter")
|
||||
, Parser.map Random (Parser.s "random")
|
||||
]
|
||||
)
|
||||
>> Maybe.withDefault NotFound
|
||||
|
||||
|
||||
toPath : Route -> String
|
||||
toPath route =
|
||||
(String.join "/" >> (++) "/") <|
|
||||
case route of
|
||||
Homepage ->
|
||||
[]
|
||||
|
||||
Counter ->
|
||||
[ "counter" ]
|
||||
|
||||
Random ->
|
||||
[ "random" ]
|
||||
|
||||
NotFound ->
|
||||
[ "not-found" ]
|
||||
|
||||
|
||||
title : Route -> String
|
||||
title route =
|
||||
case route of
|
||||
Homepage ->
|
||||
"Home"
|
||||
"/"
|
||||
|
||||
SignIn ->
|
||||
"/sign-in"
|
||||
|
||||
Counter ->
|
||||
"Counter"
|
||||
"/counter"
|
||||
|
||||
Random ->
|
||||
"Random"
|
||||
"/random"
|
||||
|
||||
NotFound ->
|
||||
"Not found"
|
||||
"/not-found"
|
||||
|
19
examples/basic/src/Utils/Cmd.elm
Normal file
19
examples/basic/src/Utils/Cmd.elm
Normal file
@ -0,0 +1,19 @@
|
||||
module Utils.Cmd exposing
|
||||
( pure
|
||||
, toCmd
|
||||
)
|
||||
|
||||
import Task
|
||||
|
||||
|
||||
pure : model -> ( model, Cmd a, Cmd b )
|
||||
pure model =
|
||||
( model
|
||||
, Cmd.none
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
toCmd : msg -> Cmd msg
|
||||
toCmd msg =
|
||||
Task.perform identity (Task.succeed msg)
|
@ -1,4 +1,27 @@
|
||||
module Application exposing (Application, create)
|
||||
module Application exposing
|
||||
( Application
|
||||
, create
|
||||
, Messages
|
||||
)
|
||||
|
||||
{-| A package for building single page apps with Elm!
|
||||
|
||||
|
||||
# Application
|
||||
|
||||
@docs Application
|
||||
|
||||
|
||||
# Creating applications
|
||||
|
||||
@docs create
|
||||
|
||||
|
||||
# Navigating all smooth-like
|
||||
|
||||
@docs Messages
|
||||
|
||||
-}
|
||||
|
||||
import Application.Page exposing (Context)
|
||||
import Browser
|
||||
@ -10,10 +33,107 @@ import Task
|
||||
import Url exposing (Url)
|
||||
|
||||
|
||||
{-| A type that's provided for type annotations!
|
||||
|
||||
Instead of `Program Flags Model Msg`, you can use this type to annotate your main method:
|
||||
|
||||
main : Application Flags Context.Model Context.Msg App.Model App.Msg
|
||||
main =
|
||||
Application.create { ... }
|
||||
|
||||
-}
|
||||
type alias Application flags contextModel contextMsg model msg =
|
||||
Program flags (Model flags contextModel model) (Msg contextMsg msg)
|
||||
|
||||
|
||||
type alias Config flags route contextModel contextMsg model msg =
|
||||
{ context :
|
||||
{ init :
|
||||
route
|
||||
-> flags
|
||||
-> ( contextModel, Cmd contextMsg )
|
||||
, update :
|
||||
Messages route (Msg contextMsg msg)
|
||||
-> route
|
||||
-> contextMsg
|
||||
-> contextModel
|
||||
-> ( contextModel, Cmd contextMsg, Cmd (Msg contextMsg msg) )
|
||||
, subscriptions :
|
||||
route
|
||||
-> contextModel
|
||||
-> Sub contextMsg
|
||||
, view :
|
||||
{ route : route
|
||||
, context : contextModel
|
||||
, toMsg : contextMsg -> Msg contextMsg msg
|
||||
, viewPage : Html (Msg contextMsg msg)
|
||||
}
|
||||
-> Html (Msg contextMsg msg)
|
||||
}
|
||||
, page :
|
||||
{ init :
|
||||
Context flags route contextModel
|
||||
-> ( model, Cmd msg, Cmd contextMsg )
|
||||
, update :
|
||||
Context flags route contextModel
|
||||
-> msg
|
||||
-> model
|
||||
-> ( model, Cmd msg, Cmd contextMsg )
|
||||
, bundle :
|
||||
Context flags route contextModel
|
||||
-> model
|
||||
-> Application.Page.Bundle msg
|
||||
}
|
||||
, route :
|
||||
{ fromUrl : Url -> route
|
||||
, toPath : route -> String
|
||||
}
|
||||
, transition : Float
|
||||
}
|
||||
|
||||
|
||||
{-| The way to create an `Application`!
|
||||
|
||||
Provide this function with a configuration, and it will bundle things up for you.
|
||||
|
||||
Here's an example (from the `examples/basic` folder of this repo):
|
||||
|
||||
main : Application Flags Context.Model Context.Msg App.Model App.Msg
|
||||
main =
|
||||
Application.create
|
||||
{ transition = 200
|
||||
, context =
|
||||
{ init = Context.init
|
||||
, update = Context.update
|
||||
, view = Context.view
|
||||
, subscriptions = Context.subscriptions
|
||||
}
|
||||
, page =
|
||||
{ init = App.init
|
||||
, update = App.update
|
||||
, bundle = App.view
|
||||
}
|
||||
, route =
|
||||
{ fromUrl = Route.fromUrl
|
||||
, toPath = Route.toPath
|
||||
}
|
||||
}
|
||||
|
||||
-}
|
||||
create :
|
||||
Config flags route contextModel contextMsg model msg
|
||||
-> Application flags contextModel contextMsg model msg
|
||||
create config =
|
||||
Browser.application
|
||||
{ init = init config
|
||||
, update = update config
|
||||
, view = view config
|
||||
, subscriptions = subscriptions config
|
||||
, onUrlChange = UrlChanged
|
||||
, onUrlRequest = UrlRequested
|
||||
}
|
||||
|
||||
|
||||
type alias Model flags contextModel model =
|
||||
{ key : Nav.Key
|
||||
, url : Url
|
||||
@ -73,45 +193,11 @@ type Msg contextMsg msg
|
||||
| PageMsg msg
|
||||
|
||||
|
||||
type alias Config flags route contextModel contextMsg model msg =
|
||||
{ context :
|
||||
{ init : route -> flags -> ( contextModel, Cmd contextMsg )
|
||||
, update : route -> contextMsg -> contextModel -> ( contextModel, Cmd contextMsg )
|
||||
, subscriptions : route -> contextModel -> Sub contextMsg
|
||||
, view :
|
||||
{ route : route
|
||||
, context : contextModel
|
||||
, toMsg : contextMsg -> Msg contextMsg msg
|
||||
, viewPage : Html (Msg contextMsg msg)
|
||||
}
|
||||
-> Html (Msg contextMsg msg)
|
||||
}
|
||||
, page :
|
||||
{ init : Context flags route contextModel -> ( model, Cmd msg, Cmd contextMsg )
|
||||
, update : Context flags route contextModel -> msg -> model -> ( model, Cmd msg, Cmd contextMsg )
|
||||
, subscriptions : Context flags route contextModel -> model -> Sub msg
|
||||
, view : Context flags route contextModel -> model -> Html msg
|
||||
}
|
||||
, toRoute : Url -> route
|
||||
, title : route -> String
|
||||
, transition : Float
|
||||
type alias Messages route msg =
|
||||
{ navigateTo : route -> Cmd msg
|
||||
}
|
||||
|
||||
|
||||
create :
|
||||
Config flags route contextModel contextMsg model msg
|
||||
-> Application flags contextModel contextMsg model msg
|
||||
create config =
|
||||
Browser.application
|
||||
{ init = init config
|
||||
, update = update config
|
||||
, view = view config
|
||||
, subscriptions = subscriptions config
|
||||
, onUrlChange = UrlChanged
|
||||
, onUrlRequest = UrlRequested
|
||||
}
|
||||
|
||||
|
||||
init :
|
||||
Config flags route contextModel contextMsg model msg
|
||||
-> flags
|
||||
@ -121,7 +207,7 @@ init :
|
||||
init config flags url key =
|
||||
let
|
||||
route =
|
||||
config.toRoute url
|
||||
config.route.fromUrl url
|
||||
|
||||
( contextModel, contextCmd ) =
|
||||
config.context.init route flags
|
||||
@ -181,7 +267,7 @@ update config msg model =
|
||||
let
|
||||
( pageModel, pageCmd, contextCmd ) =
|
||||
config.page.init
|
||||
{ route = config.toRoute url
|
||||
{ route = config.route.fromUrl url
|
||||
, flags = model.flags
|
||||
, context = model.context
|
||||
}
|
||||
@ -194,16 +280,27 @@ update config msg model =
|
||||
)
|
||||
|
||||
ContextMsg msg_ ->
|
||||
Tuple.mapBoth
|
||||
(\context -> { model | context = context })
|
||||
(Cmd.map ContextMsg)
|
||||
(config.context.update (config.toRoute model.url) msg_ model.context)
|
||||
let
|
||||
( contextModel, contextCmd, globalCmd ) =
|
||||
config.context.update
|
||||
{ navigateTo = navigateTo config model.url
|
||||
}
|
||||
(config.route.fromUrl model.url)
|
||||
msg_
|
||||
model.context
|
||||
in
|
||||
( { model | context = contextModel }
|
||||
, Cmd.batch
|
||||
[ Cmd.map ContextMsg contextCmd
|
||||
, globalCmd
|
||||
]
|
||||
)
|
||||
|
||||
PageMsg msg_ ->
|
||||
let
|
||||
( pageModel, pageCmd, contextCmd ) =
|
||||
config.page.update
|
||||
{ route = config.toRoute model.url
|
||||
{ route = config.route.fromUrl model.url
|
||||
, flags = model.flags
|
||||
, context = model.context
|
||||
}
|
||||
@ -257,15 +354,19 @@ view config model =
|
||||
|
||||
Loaded _ ->
|
||||
"1"
|
||||
|
||||
( context, pageModel ) =
|
||||
contextAndPage ( config, model )
|
||||
in
|
||||
{ title = config.title (config.toRoute model.url)
|
||||
{ title = config.page.bundle context pageModel |> .title
|
||||
, body =
|
||||
[ div
|
||||
[ Attr.style "transition" (transitionProp config.transition)
|
||||
[ Attr.class "app"
|
||||
, Attr.style "transition" (transitionProp config.transition)
|
||||
, Attr.style "opacity" (layoutOpacity model.page)
|
||||
]
|
||||
[ config.context.view
|
||||
{ route = config.toRoute model.url
|
||||
{ route = config.route.fromUrl model.url
|
||||
, toMsg = ContextMsg
|
||||
, context = model.context
|
||||
, viewPage =
|
||||
@ -274,13 +375,7 @@ view config model =
|
||||
, Attr.style "opacity" (pageOpacity model.page)
|
||||
]
|
||||
[ Html.map PageMsg
|
||||
(config.page.view
|
||||
{ route = config.toRoute model.url
|
||||
, flags = model.flags
|
||||
, context = model.context
|
||||
}
|
||||
(unwrap model.page)
|
||||
)
|
||||
(config.page.bundle context pageModel |> .view)
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -293,14 +388,39 @@ subscriptions :
|
||||
-> Model flags contextModel model
|
||||
-> Sub (Msg contextMsg msg)
|
||||
subscriptions config model =
|
||||
let
|
||||
( context, pageModel ) =
|
||||
contextAndPage ( config, model )
|
||||
in
|
||||
Sub.batch
|
||||
[ Sub.map ContextMsg (config.context.subscriptions (config.toRoute model.url) model.context)
|
||||
, Sub.map PageMsg
|
||||
(config.page.subscriptions
|
||||
{ route = config.toRoute model.url
|
||||
, flags = model.flags
|
||||
, context = model.context
|
||||
}
|
||||
(unwrap model.page)
|
||||
)
|
||||
[ Sub.map ContextMsg (config.context.subscriptions (config.route.fromUrl model.url) model.context)
|
||||
, Sub.map PageMsg (config.page.bundle context pageModel |> .subscriptions)
|
||||
]
|
||||
|
||||
|
||||
|
||||
-- UTILS
|
||||
|
||||
|
||||
contextAndPage :
|
||||
( Config flags route contextModel contextMsg model msg, Model flags contextModel model )
|
||||
-> ( Application.Page.Context flags route contextModel, model )
|
||||
contextAndPage ( config, model ) =
|
||||
( { route = config.route.fromUrl model.url
|
||||
, flags = model.flags
|
||||
, context = model.context
|
||||
}
|
||||
, unwrap model.page
|
||||
)
|
||||
|
||||
|
||||
navigateTo :
|
||||
Config flags route contextModel contextMsg model msg
|
||||
-> Url
|
||||
-> route
|
||||
-> Cmd (Msg contextMsg msg)
|
||||
navigateTo config url route =
|
||||
Task.succeed (config.route.toPath route)
|
||||
|> Task.map (\path -> { url | path = path })
|
||||
|> Task.map Browser.Internal
|
||||
|> Task.perform UrlRequested
|
||||
|
@ -1,16 +1,38 @@
|
||||
module Application.Page exposing
|
||||
( Context
|
||||
, Page
|
||||
, element
|
||||
, init
|
||||
, page
|
||||
, sandbox
|
||||
, static
|
||||
, subscriptions
|
||||
, update
|
||||
, view
|
||||
( static, sandbox, element, page
|
||||
, init, update, bundle
|
||||
, Context
|
||||
, Bundle
|
||||
)
|
||||
|
||||
{-| A package for building single page apps with Elm!
|
||||
|
||||
|
||||
# Page
|
||||
|
||||
These functions convert your pages into one consistent `Page` type.
|
||||
|
||||
This makes writing top-level functions like `init`, `update`, `view`, and `subscriptions` easy, without making pages themselves unnecessarily complex.
|
||||
|
||||
You can check out [a full example here](https://github.com/ryannhg/elm-app/tree/master/examples/basic) to understand how these functions are used.
|
||||
|
||||
@docs static, sandbox, element, page
|
||||
|
||||
|
||||
# Helpers
|
||||
|
||||
@docs init, update, bundle
|
||||
|
||||
|
||||
# Related types
|
||||
|
||||
@docs Context
|
||||
|
||||
@docs Bundle
|
||||
|
||||
-}
|
||||
|
||||
import Browser
|
||||
import Html exposing (Html)
|
||||
|
||||
|
||||
@ -22,7 +44,8 @@ type alias Context flags route contextModel =
|
||||
|
||||
|
||||
type alias Page route flags contextModel contextMsg model msg appModel appMsg =
|
||||
{ init : Context flags route contextModel -> ( model, Cmd msg, Cmd contextMsg )
|
||||
{ title : Context flags route contextModel -> model -> String
|
||||
, init : Context flags route contextModel -> ( model, Cmd msg, Cmd contextMsg )
|
||||
, update : Context flags route contextModel -> msg -> model -> ( model, Cmd msg, Cmd contextMsg )
|
||||
, subscriptions : Context flags route contextModel -> model -> Sub msg
|
||||
, view : Context flags route contextModel -> model -> Html msg
|
||||
@ -37,11 +60,11 @@ type alias Page route flags contextModel contextMsg model msg appModel appMsg =
|
||||
|
||||
init :
|
||||
{ page : Page route flags contextModel contextMsg model msg appModel appMsg
|
||||
, context : Context flags route contextModel
|
||||
}
|
||||
-> Context flags route contextModel
|
||||
-> ( appModel, Cmd appMsg, Cmd contextMsg )
|
||||
init config context =
|
||||
config.page.init context
|
||||
init config =
|
||||
config.page.init config.context
|
||||
|> mapTruple
|
||||
{ fromMsg = config.page.toMsg
|
||||
, fromModel = config.page.toModel
|
||||
@ -52,37 +75,46 @@ update :
|
||||
{ page : Page route flags contextModel contextMsg model msg appModel appMsg
|
||||
, msg : msg
|
||||
, model : model
|
||||
, context : Context flags route contextModel
|
||||
}
|
||||
-> Context flags route contextModel
|
||||
-> ( appModel, Cmd appMsg, Cmd contextMsg )
|
||||
update config context =
|
||||
config.page.update context config.msg config.model
|
||||
update config =
|
||||
config.page.update config.context config.msg config.model
|
||||
|> mapTruple
|
||||
{ fromMsg = config.page.toMsg
|
||||
, fromModel = config.page.toModel
|
||||
}
|
||||
|
||||
|
||||
subscriptions :
|
||||
{ page : Page route flags contextModel contextMsg model msg appModel appMsg
|
||||
, model : model
|
||||
type alias Bundle appMsg =
|
||||
{ title : String
|
||||
, view : Html appMsg
|
||||
, subscriptions : Sub appMsg
|
||||
}
|
||||
-> Context flags route contextModel
|
||||
-> Sub appMsg
|
||||
subscriptions config context =
|
||||
config.page.subscriptions context config.model
|
||||
|> Sub.map config.page.toMsg
|
||||
|
||||
|
||||
view :
|
||||
bundle :
|
||||
{ page : Page route flags contextModel contextMsg model msg appModel appMsg
|
||||
, model : model
|
||||
, context : Context flags route contextModel
|
||||
}
|
||||
-> Bundle appMsg
|
||||
bundle config =
|
||||
{ title =
|
||||
config.page.title
|
||||
config.context
|
||||
config.model
|
||||
, view =
|
||||
Html.map config.page.toMsg <|
|
||||
config.page.view
|
||||
config.context
|
||||
config.model
|
||||
, subscriptions =
|
||||
Sub.map config.page.toMsg <|
|
||||
config.page.subscriptions
|
||||
config.context
|
||||
config.model
|
||||
}
|
||||
-> Context flags route contextModel
|
||||
-> Html appMsg
|
||||
view config context =
|
||||
config.page.view context config.model
|
||||
|> Html.map config.page.toMsg
|
||||
|
||||
|
||||
|
||||
@ -90,12 +122,14 @@ view config context =
|
||||
|
||||
|
||||
static :
|
||||
{ view : Html Never
|
||||
{ title : String
|
||||
, view : Html Never
|
||||
, toModel : () -> appModel
|
||||
}
|
||||
-> Page route flags contextModel contextMsg () Never appModel appMsg
|
||||
static config =
|
||||
{ init = \c -> ( (), Cmd.none, Cmd.none )
|
||||
{ title = \c m -> config.title
|
||||
, init = \c -> ( (), Cmd.none, Cmd.none )
|
||||
, update = \c m model -> ( model, Cmd.none, Cmd.none )
|
||||
, subscriptions = \c m -> Sub.none
|
||||
, view = \c m -> Html.map never config.view
|
||||
@ -105,7 +139,8 @@ static config =
|
||||
|
||||
|
||||
sandbox :
|
||||
{ init : model
|
||||
{ title : model -> String
|
||||
, init : model
|
||||
, update : msg -> model -> model
|
||||
, view : model -> Html msg
|
||||
, toMsg : msg -> appMsg
|
||||
@ -113,7 +148,8 @@ sandbox :
|
||||
}
|
||||
-> Page route flags contextModel contextMsg model msg appModel appMsg
|
||||
sandbox config =
|
||||
{ init = \c -> ( config.init, Cmd.none, Cmd.none )
|
||||
{ title = \c model -> config.title model
|
||||
, init = \c -> ( config.init, Cmd.none, Cmd.none )
|
||||
, update = \c msg model -> ( config.update msg model, Cmd.none, Cmd.none )
|
||||
, subscriptions = \c m -> Sub.none
|
||||
, view = \c model -> config.view model
|
||||
@ -123,7 +159,8 @@ sandbox config =
|
||||
|
||||
|
||||
element :
|
||||
{ init : flags -> ( model, Cmd msg )
|
||||
{ title : model -> String
|
||||
, init : flags -> ( model, Cmd msg )
|
||||
, update : msg -> model -> ( model, Cmd msg )
|
||||
, subscriptions : model -> Sub msg
|
||||
, view : model -> Html msg
|
||||
@ -136,7 +173,8 @@ element config =
|
||||
appendCmd ( model, cmd ) =
|
||||
( model, cmd, Cmd.none )
|
||||
in
|
||||
{ init = \c -> config.init c.flags |> appendCmd
|
||||
{ title = \c model -> config.title model
|
||||
, init = \c -> config.init c.flags |> appendCmd
|
||||
, update = \c msg model -> config.update msg model |> appendCmd
|
||||
, subscriptions = \c model -> config.subscriptions model
|
||||
, view = \c model -> config.view model
|
||||
@ -146,8 +184,9 @@ element config =
|
||||
|
||||
|
||||
page :
|
||||
{ init : Context flags route contextModel -> ( model, Cmd msg )
|
||||
, update : Context flags route contextModel -> msg -> model -> ( model, Cmd msg )
|
||||
{ title : Context flags route contextModel -> model -> String
|
||||
, init : Context flags route contextModel -> ( model, Cmd msg, Cmd contextMsg )
|
||||
, update : Context flags route contextModel -> msg -> model -> ( model, Cmd msg, Cmd contextMsg )
|
||||
, subscriptions : Context flags route contextModel -> model -> Sub msg
|
||||
, view : Context flags route contextModel -> model -> Html msg
|
||||
, toMsg : msg -> appMsg
|
||||
@ -159,8 +198,9 @@ page config =
|
||||
appendCmd ( model, cmd ) =
|
||||
( model, cmd, Cmd.none )
|
||||
in
|
||||
{ init = \c -> config.init c |> appendCmd
|
||||
, update = \c msg model -> config.update c msg model |> appendCmd
|
||||
{ title = config.title
|
||||
, init = config.init
|
||||
, update = config.update
|
||||
, subscriptions = \c model -> config.subscriptions c model
|
||||
, view = \c model -> config.view c model
|
||||
, toMsg = config.toMsg
|
||||
|
Loading…
Reference in New Issue
Block a user