mirror of
https://github.com/ryannhg/elm-spa.git
synced 2024-11-29 13:34:42 +03:00
add in example
This commit is contained in:
commit
3ce88f8e24
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.cache
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
elm-stuff
|
||||||
|
node_modules
|
192
README.md
Normal file
192
README.md
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
# ryannhg/elm-app
|
||||||
|
> a way to build single page apps with Elm.
|
||||||
|
|
||||||
|
## try it out
|
||||||
|
|
||||||
|
```
|
||||||
|
elm install ryannhg/elm-app
|
||||||
|
```
|
||||||
|
|
||||||
|
## quick overview
|
||||||
|
|
||||||
|
this package is a wrapper around Elm's `Browser.application`, adding in page transitions and utilities for adding in new pages and routes.
|
||||||
|
|
||||||
|
here's what it looks like to use it:
|
||||||
|
|
||||||
|
|
||||||
|
### src/Main.elm
|
||||||
|
|
||||||
|
This is the entrypoint to the app, it imports:
|
||||||
|
|
||||||
|
- `Application` - this package
|
||||||
|
- `App` - the top level `Model`, `Msg`, `init`, `update`, `subscriptions`, and `view`
|
||||||
|
- `
|
||||||
|
|
||||||
|
```elm
|
||||||
|
module Main exposing (main)
|
||||||
|
|
||||||
|
import Application exposing (Application)
|
||||||
|
|
||||||
|
import App
|
||||||
|
import Context
|
||||||
|
import Route
|
||||||
|
import Flags exposing (Flags)
|
||||||
|
|
||||||
|
|
||||||
|
main : Application Flags Context.Model Context.Msg App.Model App.Msg
|
||||||
|
main =
|
||||||
|
Application.create
|
||||||
|
{ transition = 300
|
||||||
|
, toRoute = Route.fromUrl
|
||||||
|
, title = Route.title
|
||||||
|
, context =
|
||||||
|
{ init = Context.init
|
||||||
|
, update = Context.update
|
||||||
|
, view = Context.view
|
||||||
|
, subscriptions = Context.subscriptions
|
||||||
|
}
|
||||||
|
, page =
|
||||||
|
{ init = App.init
|
||||||
|
, update = App.update
|
||||||
|
, view = App.view
|
||||||
|
, subscriptions = App.subscriptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### src/Pages/Homepage.elm
|
||||||
|
> Uses `Application.Page.static`
|
||||||
|
|
||||||
|
The homepage is static, so it's just a `view`:
|
||||||
|
|
||||||
|
```elm
|
||||||
|
module Pages.Homepage exposing (view)
|
||||||
|
|
||||||
|
import Html exposing (Html)
|
||||||
|
|
||||||
|
|
||||||
|
view : Html Never
|
||||||
|
view =
|
||||||
|
Html.text "Homepage!"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### src/Pages/Counter.elm
|
||||||
|
> Uses `Application.Page.Sandbox`
|
||||||
|
|
||||||
|
The counter page doesn't have any side effects:
|
||||||
|
|
||||||
|
```elm
|
||||||
|
module Pages.Counter exposing (Model, Msg, init, update, view)
|
||||||
|
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Events as Events
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ counter : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Increment
|
||||||
|
| Decrement
|
||||||
|
|
||||||
|
|
||||||
|
init : Model
|
||||||
|
init =
|
||||||
|
{ counter = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> Model
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Decrement ->
|
||||||
|
{ model | counter = model.counter - 1 }
|
||||||
|
|
||||||
|
Increment ->
|
||||||
|
{ model | counter = model.counter + 1 }
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
div []
|
||||||
|
[ button [ Events.onClick Decrement ] [ text "-" ]
|
||||||
|
, text (String.fromInt model.counter)
|
||||||
|
, button [ Events.onClick Increment ] [ text "+" ]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### src/Pages/Random.elm
|
||||||
|
> Uses `Application.Page.element`
|
||||||
|
|
||||||
|
The random page doesn't need to update the context of the application:
|
||||||
|
|
||||||
|
```elm
|
||||||
|
module Pages.Random exposing
|
||||||
|
( Model
|
||||||
|
, Msg
|
||||||
|
, init
|
||||||
|
, subscriptions
|
||||||
|
, update
|
||||||
|
, view
|
||||||
|
)
|
||||||
|
|
||||||
|
import Flags exposing (Flags)
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Events as Events
|
||||||
|
import Random
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ roll : Maybe Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Roll
|
||||||
|
| GotOutcome Int
|
||||||
|
|
||||||
|
|
||||||
|
init : Flags -> ( Model, Cmd Msg )
|
||||||
|
init _ =
|
||||||
|
( { roll = Nothing }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
rollDice : Model -> ( Model, Cmd Msg )
|
||||||
|
rollDice model =
|
||||||
|
( model
|
||||||
|
, Random.generate GotOutcome (Random.int 1 6)
|
||||||
|
)
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Roll ->
|
||||||
|
rollDice model
|
||||||
|
|
||||||
|
GotOutcome value ->
|
||||||
|
( { model | roll = Just value }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
div []
|
||||||
|
[ button [ Events.onClick Roll ] [ text "Roll" ]
|
||||||
|
, p []
|
||||||
|
[ case model.roll of
|
||||||
|
Just roll ->
|
||||||
|
text (String.fromInt roll)
|
||||||
|
Nothing ->
|
||||||
|
text "Click the button!"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
subscriptions : Model -> Sub Msg
|
||||||
|
subscriptions model =
|
||||||
|
Sub.none
|
||||||
|
```
|
24
elm.json
Normal file
24
elm.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"type": "application",
|
||||||
|
"source-directories": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"elm-version": "0.19.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"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test-dependencies": {
|
||||||
|
"direct": {},
|
||||||
|
"indirect": {}
|
||||||
|
}
|
||||||
|
}
|
4
examples/README.md
Normal file
4
examples/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# examples
|
||||||
|
> some examples of how to use this package.
|
||||||
|
|
||||||
|
- [basic](./basic)
|
8
examples/basic/README.md
Normal file
8
examples/basic/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# examples/basic
|
||||||
|
> an intro into an app using `ryannhg/elm-app`
|
||||||
|
|
||||||
|
## how to run
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
|
||||||
|
1. `npm run dev`
|
26
examples/basic/elm.json
Normal file
26
examples/basic/elm.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"type": "application",
|
||||||
|
"source-directories": [
|
||||||
|
"src",
|
||||||
|
"../../src"
|
||||||
|
],
|
||||||
|
"elm-version": "0.19.0",
|
||||||
|
"dependencies": {
|
||||||
|
"direct": {
|
||||||
|
"elm/browser": "1.0.1",
|
||||||
|
"elm/core": "1.0.2",
|
||||||
|
"elm/html": "1.0.0",
|
||||||
|
"elm/random": "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"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test-dependencies": {
|
||||||
|
"direct": {},
|
||||||
|
"indirect": {}
|
||||||
|
}
|
||||||
|
}
|
13
examples/basic/index.html
Normal file
13
examples/basic/index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script src="./main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
5
examples/basic/main.js
Normal file
5
examples/basic/main.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { Elm } from './src/Main.elm'
|
||||||
|
|
||||||
|
Elm.Main.init({
|
||||||
|
node: document.getElementById('app')
|
||||||
|
})
|
7585
examples/basic/package-lock.json
generated
Normal file
7585
examples/basic/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
examples/basic/package.json
Normal file
19
examples/basic/package.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "application",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "parcel index.html"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"elm": "^0.19.0-no-deps",
|
||||||
|
"elm-format": "^0.8.2",
|
||||||
|
"elm-hot": "^1.1.2",
|
||||||
|
"node-elm-compiler": "^5.0.4",
|
||||||
|
"parcel-bundler": "^1.12.3"
|
||||||
|
}
|
||||||
|
}
|
223
examples/basic/src/App.elm
Normal file
223
examples/basic/src/App.elm
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
module App exposing
|
||||||
|
( Model
|
||||||
|
, Msg
|
||||||
|
, init
|
||||||
|
, subscriptions
|
||||||
|
, update
|
||||||
|
, view
|
||||||
|
)
|
||||||
|
|
||||||
|
import Application.Page as Page exposing (Context)
|
||||||
|
import Context
|
||||||
|
import Flags exposing (Flags)
|
||||||
|
import Html exposing (Html)
|
||||||
|
import Pages.Counter
|
||||||
|
import Pages.Homepage
|
||||||
|
import Pages.NotFound
|
||||||
|
import Pages.Random
|
||||||
|
import Route exposing (Route)
|
||||||
|
|
||||||
|
|
||||||
|
type Model
|
||||||
|
= HomepageModel ()
|
||||||
|
| CounterModel Pages.Counter.Model
|
||||||
|
| RandomModel Pages.Random.Model
|
||||||
|
| NotFoundModel ()
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= HomepageMsg Never
|
||||||
|
| CounterMsg Pages.Counter.Msg
|
||||||
|
| RandomMsg Pages.Random.Msg
|
||||||
|
| NotFoundMsg Never
|
||||||
|
|
||||||
|
|
||||||
|
pages =
|
||||||
|
{ homepage =
|
||||||
|
Page.static
|
||||||
|
{ view = Pages.Homepage.view
|
||||||
|
, toModel = HomepageModel
|
||||||
|
}
|
||||||
|
, counter =
|
||||||
|
Page.sandbox
|
||||||
|
{ init = Pages.Counter.init
|
||||||
|
, update = Pages.Counter.update
|
||||||
|
, view = Pages.Counter.view
|
||||||
|
, toModel = CounterModel
|
||||||
|
, toMsg = CounterMsg
|
||||||
|
}
|
||||||
|
, random =
|
||||||
|
Page.element
|
||||||
|
{ init = Pages.Random.init
|
||||||
|
, update = Pages.Random.update
|
||||||
|
, subscriptions = Pages.Random.subscriptions
|
||||||
|
, view = Pages.Random.view
|
||||||
|
, toModel = RandomModel
|
||||||
|
, toMsg = RandomMsg
|
||||||
|
}
|
||||||
|
, notFound =
|
||||||
|
Page.static
|
||||||
|
{ view = Pages.NotFound.view
|
||||||
|
, toModel = NotFoundModel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init :
|
||||||
|
Context Flags Route Context.Model
|
||||||
|
-> ( Model, Cmd Msg, Cmd Context.Msg )
|
||||||
|
init context =
|
||||||
|
case context.route of
|
||||||
|
Route.Homepage ->
|
||||||
|
Page.init
|
||||||
|
{ page = pages.homepage }
|
||||||
|
context
|
||||||
|
|
||||||
|
Route.Counter ->
|
||||||
|
Page.init
|
||||||
|
{ page = pages.counter }
|
||||||
|
context
|
||||||
|
|
||||||
|
Route.Random ->
|
||||||
|
Page.init
|
||||||
|
{ page = pages.random }
|
||||||
|
context
|
||||||
|
|
||||||
|
Route.NotFound ->
|
||||||
|
Page.init
|
||||||
|
{ page = pages.notFound }
|
||||||
|
context
|
||||||
|
|
||||||
|
|
||||||
|
update :
|
||||||
|
Context Flags Route Context.Model
|
||||||
|
-> Msg
|
||||||
|
-> Model
|
||||||
|
-> ( Model, Cmd Msg, Cmd Context.Msg )
|
||||||
|
update context appMsg appModel =
|
||||||
|
case ( appModel, appMsg ) of
|
||||||
|
( HomepageModel model, HomepageMsg msg ) ->
|
||||||
|
Page.update
|
||||||
|
{ page = pages.homepage
|
||||||
|
, msg = msg
|
||||||
|
, model = model
|
||||||
|
}
|
||||||
|
context
|
||||||
|
|
||||||
|
( HomepageModel _, _ ) ->
|
||||||
|
( appModel
|
||||||
|
, Cmd.none
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
( CounterModel model, CounterMsg msg ) ->
|
||||||
|
Page.update
|
||||||
|
{ page = pages.counter
|
||||||
|
, msg = msg
|
||||||
|
, model = model
|
||||||
|
}
|
||||||
|
context
|
||||||
|
|
||||||
|
( CounterModel _, _ ) ->
|
||||||
|
( appModel
|
||||||
|
, Cmd.none
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
( RandomModel model, RandomMsg msg ) ->
|
||||||
|
Page.update
|
||||||
|
{ page = pages.random
|
||||||
|
, msg = msg
|
||||||
|
, model = model
|
||||||
|
}
|
||||||
|
context
|
||||||
|
|
||||||
|
( RandomModel _, _ ) ->
|
||||||
|
( appModel
|
||||||
|
, Cmd.none
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
( NotFoundModel model, NotFoundMsg msg ) ->
|
||||||
|
Page.update
|
||||||
|
{ page = pages.notFound
|
||||||
|
, msg = msg
|
||||||
|
, model = model
|
||||||
|
}
|
||||||
|
context
|
||||||
|
|
||||||
|
( NotFoundModel _, _ ) ->
|
||||||
|
( appModel
|
||||||
|
, Cmd.none
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
subscriptions :
|
||||||
|
Context Flags Route Context.Model
|
||||||
|
-> Model
|
||||||
|
-> Sub Msg
|
||||||
|
subscriptions context appModel =
|
||||||
|
case appModel of
|
||||||
|
HomepageModel model ->
|
||||||
|
Page.subscriptions
|
||||||
|
{ page = pages.homepage
|
||||||
|
, model = model
|
||||||
|
}
|
||||||
|
context
|
||||||
|
|
||||||
|
CounterModel model ->
|
||||||
|
Page.subscriptions
|
||||||
|
{ page = pages.counter
|
||||||
|
, model = model
|
||||||
|
}
|
||||||
|
context
|
||||||
|
|
||||||
|
RandomModel model ->
|
||||||
|
Page.subscriptions
|
||||||
|
{ page = pages.random
|
||||||
|
, model = model
|
||||||
|
}
|
||||||
|
context
|
||||||
|
|
||||||
|
NotFoundModel model ->
|
||||||
|
Page.subscriptions
|
||||||
|
{ page = pages.notFound
|
||||||
|
, model = model
|
||||||
|
}
|
||||||
|
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
|
108
examples/basic/src/Context.elm
Normal file
108
examples/basic/src/Context.elm
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
module Context exposing
|
||||||
|
( Model
|
||||||
|
, Msg
|
||||||
|
, init
|
||||||
|
, subscriptions
|
||||||
|
, update
|
||||||
|
, view
|
||||||
|
)
|
||||||
|
|
||||||
|
import Flags exposing (Flags)
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes as Attr
|
||||||
|
import Html.Events as Events
|
||||||
|
import Route exposing (Route)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ user : Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= SignIn String
|
||||||
|
| SignOut
|
||||||
|
|
||||||
|
|
||||||
|
init : Route -> Flags -> ( Model, Cmd Msg )
|
||||||
|
init route flags =
|
||||||
|
( { user = Nothing }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
update : Route -> Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update route msg model =
|
||||||
|
case msg of
|
||||||
|
SignIn user ->
|
||||||
|
( { model | user = Just user }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
SignOut ->
|
||||||
|
( { model | user = Nothing }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
view :
|
||||||
|
{ route : Route
|
||||||
|
, context : Model
|
||||||
|
, toMsg : Msg -> msg
|
||||||
|
, viewPage : Html msg
|
||||||
|
}
|
||||||
|
-> Html msg
|
||||||
|
view { context, route, toMsg, viewPage } =
|
||||||
|
div [ Attr.class "layout" ]
|
||||||
|
[ Html.map toMsg (viewNavbar route context)
|
||||||
|
, br [] []
|
||||||
|
, viewPage
|
||||||
|
, br [] []
|
||||||
|
, Html.map toMsg (viewFooter context)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewNavbar : Route -> Model -> Html Msg
|
||||||
|
viewNavbar currentRoute model =
|
||||||
|
header [ Attr.class "navbar" ]
|
||||||
|
[ ul []
|
||||||
|
(List.map
|
||||||
|
(viewLink currentRoute)
|
||||||
|
[ Route.Homepage, Route.Counter, Route.Random ]
|
||||||
|
)
|
||||||
|
, case model.user of
|
||||||
|
Just _ ->
|
||||||
|
button [ Events.onClick SignOut ] [ text <| "Sign out" ]
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
button [ Events.onClick (SignIn "Ryan") ] [ 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"
|
||||||
|
|
||||||
|
else
|
||||||
|
"normal"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
[ text (Route.title route) ]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewFooter : Model -> Html Msg
|
||||||
|
viewFooter model =
|
||||||
|
footer [ Attr.class "footer" ]
|
||||||
|
[ model.user |> Maybe.withDefault "Not signed in" |> text
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
subscriptions : Route -> Model -> Sub Msg
|
||||||
|
subscriptions route model =
|
||||||
|
Sub.none
|
5
examples/basic/src/Flags.elm
Normal file
5
examples/basic/src/Flags.elm
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module Flags exposing (Flags)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Flags =
|
||||||
|
()
|
32
examples/basic/src/Main.elm
Normal file
32
examples/basic/src/Main.elm
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
module Main exposing (main)
|
||||||
|
|
||||||
|
import App
|
||||||
|
import Application exposing (Application)
|
||||||
|
import Application.Page exposing (Context)
|
||||||
|
import Context
|
||||||
|
import Flags exposing (Flags)
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes as Attr
|
||||||
|
import Html.Events as Events
|
||||||
|
import Route exposing (Route)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
, view = App.view
|
||||||
|
, subscriptions = App.subscriptions
|
||||||
|
}
|
||||||
|
, toRoute = Route.fromUrl
|
||||||
|
, title = Route.title
|
||||||
|
}
|
39
examples/basic/src/Pages/Counter.elm
Normal file
39
examples/basic/src/Pages/Counter.elm
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
module Pages.Counter exposing (Model, Msg, init, update, view)
|
||||||
|
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Events as Events
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ counter : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Increment
|
||||||
|
| Decrement
|
||||||
|
|
||||||
|
|
||||||
|
init : Model
|
||||||
|
init =
|
||||||
|
{ counter = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> Model
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Decrement ->
|
||||||
|
{ model | counter = model.counter - 1 }
|
||||||
|
|
||||||
|
Increment ->
|
||||||
|
{ model | counter = model.counter + 1 }
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
div []
|
||||||
|
[ button [ Events.onClick Decrement ] [ text "-" ]
|
||||||
|
, text (String.fromInt model.counter)
|
||||||
|
, button [ Events.onClick Increment ] [ text "+" ]
|
||||||
|
]
|
8
examples/basic/src/Pages/Homepage.elm
Normal file
8
examples/basic/src/Pages/Homepage.elm
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module Pages.Homepage exposing (view)
|
||||||
|
|
||||||
|
import Html exposing (Html)
|
||||||
|
|
||||||
|
|
||||||
|
view : Html Never
|
||||||
|
view =
|
||||||
|
Html.text "Homepage!"
|
8
examples/basic/src/Pages/NotFound.elm
Normal file
8
examples/basic/src/Pages/NotFound.elm
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module Pages.NotFound exposing (view)
|
||||||
|
|
||||||
|
import Html exposing (Html)
|
||||||
|
|
||||||
|
|
||||||
|
view : Html Never
|
||||||
|
view =
|
||||||
|
Html.text "Page not found..."
|
67
examples/basic/src/Pages/Random.elm
Normal file
67
examples/basic/src/Pages/Random.elm
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
module Pages.Random exposing
|
||||||
|
( Model
|
||||||
|
, Msg
|
||||||
|
, init
|
||||||
|
, subscriptions
|
||||||
|
, update
|
||||||
|
, view
|
||||||
|
)
|
||||||
|
|
||||||
|
import Flags exposing (Flags)
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Events as Events
|
||||||
|
import Random
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ roll : Maybe Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Roll
|
||||||
|
| GotOutcome Int
|
||||||
|
|
||||||
|
|
||||||
|
init : Flags -> ( Model, Cmd Msg )
|
||||||
|
init _ =
|
||||||
|
( { roll = Nothing }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
rollDice : Model -> ( Model, Cmd Msg )
|
||||||
|
rollDice model =
|
||||||
|
( model
|
||||||
|
, Random.generate GotOutcome (Random.int 1 6)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Roll ->
|
||||||
|
rollDice model
|
||||||
|
|
||||||
|
GotOutcome value ->
|
||||||
|
( { model | roll = Just value }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
subscriptions : Model -> Sub Msg
|
||||||
|
subscriptions model =
|
||||||
|
Sub.none
|
58
examples/basic/src/Route.elm
Normal file
58
examples/basic/src/Route.elm
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
module Route exposing (Route(..), fromUrl, title, toPath)
|
||||||
|
|
||||||
|
import Url exposing (Url)
|
||||||
|
import Url.Parser as Parser exposing (Parser)
|
||||||
|
|
||||||
|
|
||||||
|
type Route
|
||||||
|
= Homepage
|
||||||
|
| Counter
|
||||||
|
| Random
|
||||||
|
| NotFound
|
||||||
|
|
||||||
|
|
||||||
|
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")
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
Counter ->
|
||||||
|
"Counter"
|
||||||
|
|
||||||
|
Random ->
|
||||||
|
"Random"
|
||||||
|
|
||||||
|
NotFound ->
|
||||||
|
"Not found"
|
306
src/Application.elm
Normal file
306
src/Application.elm
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
module Application exposing (Application, create)
|
||||||
|
|
||||||
|
import Application.Page exposing (Context)
|
||||||
|
import Browser
|
||||||
|
import Browser.Navigation as Nav
|
||||||
|
import Html exposing (Html, div)
|
||||||
|
import Html.Attributes as Attr
|
||||||
|
import Process
|
||||||
|
import Task
|
||||||
|
import Url exposing (Url)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Application flags contextModel contextMsg model msg =
|
||||||
|
Program flags (Model flags contextModel model) (Msg contextMsg msg)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model flags contextModel model =
|
||||||
|
{ key : Nav.Key
|
||||||
|
, url : Url
|
||||||
|
, flags : flags
|
||||||
|
, context : contextModel
|
||||||
|
, page : Loadable model
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Loadable a
|
||||||
|
= FirstLoad a
|
||||||
|
| Loading a
|
||||||
|
| Loaded a
|
||||||
|
|
||||||
|
|
||||||
|
isFirstLoad : Loadable a -> Bool
|
||||||
|
isFirstLoad loadable =
|
||||||
|
case loadable of
|
||||||
|
FirstLoad _ ->
|
||||||
|
True
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
False
|
||||||
|
|
||||||
|
|
||||||
|
unwrap : Loadable a -> a
|
||||||
|
unwrap loadable =
|
||||||
|
case loadable of
|
||||||
|
FirstLoad a ->
|
||||||
|
a
|
||||||
|
|
||||||
|
Loading a ->
|
||||||
|
a
|
||||||
|
|
||||||
|
Loaded a ->
|
||||||
|
a
|
||||||
|
|
||||||
|
|
||||||
|
map : (a -> b) -> Loadable a -> Loadable b
|
||||||
|
map fn loadable =
|
||||||
|
case loadable of
|
||||||
|
FirstLoad a ->
|
||||||
|
FirstLoad (fn a)
|
||||||
|
|
||||||
|
Loading a ->
|
||||||
|
Loading (fn a)
|
||||||
|
|
||||||
|
Loaded a ->
|
||||||
|
Loaded (fn a)
|
||||||
|
|
||||||
|
|
||||||
|
type Msg contextMsg msg
|
||||||
|
= UrlChanged Url
|
||||||
|
| UrlRequested Browser.UrlRequest
|
||||||
|
| PageLoaded Url
|
||||||
|
| ContextMsg contextMsg
|
||||||
|
| 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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
-> Url
|
||||||
|
-> Nav.Key
|
||||||
|
-> ( Model flags contextModel model, Cmd (Msg contextMsg msg) )
|
||||||
|
init config flags url key =
|
||||||
|
let
|
||||||
|
route =
|
||||||
|
config.toRoute url
|
||||||
|
|
||||||
|
( contextModel, contextCmd ) =
|
||||||
|
config.context.init route flags
|
||||||
|
|
||||||
|
( pageModel, pageCmd, pageContextCmd ) =
|
||||||
|
config.page.init
|
||||||
|
{ route = route
|
||||||
|
, flags = flags
|
||||||
|
, context = contextModel
|
||||||
|
}
|
||||||
|
in
|
||||||
|
( { url = url
|
||||||
|
, key = key
|
||||||
|
, flags = flags
|
||||||
|
, context = contextModel
|
||||||
|
, page = FirstLoad pageModel
|
||||||
|
}
|
||||||
|
, Cmd.batch
|
||||||
|
[ delay config.transition (PageLoaded url)
|
||||||
|
, Cmd.map ContextMsg contextCmd
|
||||||
|
, Cmd.map ContextMsg pageContextCmd
|
||||||
|
, Cmd.map PageMsg pageCmd
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
delay : Float -> msg -> Cmd msg
|
||||||
|
delay ms msg =
|
||||||
|
Task.perform (\_ -> msg) (Process.sleep ms)
|
||||||
|
|
||||||
|
|
||||||
|
update :
|
||||||
|
Config flags route contextModel contextMsg model msg
|
||||||
|
-> Msg contextMsg msg
|
||||||
|
-> Model flags contextModel model
|
||||||
|
-> ( Model flags contextModel model, Cmd (Msg contextMsg msg) )
|
||||||
|
update config msg model =
|
||||||
|
case msg of
|
||||||
|
UrlRequested urlRequest ->
|
||||||
|
case urlRequest of
|
||||||
|
Browser.Internal url ->
|
||||||
|
( model
|
||||||
|
, Nav.pushUrl model.key (Url.toString url)
|
||||||
|
)
|
||||||
|
|
||||||
|
Browser.External url ->
|
||||||
|
( model
|
||||||
|
, Nav.load url
|
||||||
|
)
|
||||||
|
|
||||||
|
UrlChanged url ->
|
||||||
|
( { model | page = Loading (unwrap model.page) }
|
||||||
|
, delay config.transition (PageLoaded url)
|
||||||
|
)
|
||||||
|
|
||||||
|
PageLoaded url ->
|
||||||
|
let
|
||||||
|
( pageModel, pageCmd, contextCmd ) =
|
||||||
|
config.page.init
|
||||||
|
{ route = config.toRoute url
|
||||||
|
, flags = model.flags
|
||||||
|
, context = model.context
|
||||||
|
}
|
||||||
|
in
|
||||||
|
( { model | url = url, page = Loaded pageModel }
|
||||||
|
, Cmd.batch
|
||||||
|
[ Cmd.map PageMsg pageCmd
|
||||||
|
, Cmd.map ContextMsg contextCmd
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
ContextMsg msg_ ->
|
||||||
|
Tuple.mapBoth
|
||||||
|
(\context -> { model | context = context })
|
||||||
|
(Cmd.map ContextMsg)
|
||||||
|
(config.context.update (config.toRoute model.url) msg_ model.context)
|
||||||
|
|
||||||
|
PageMsg msg_ ->
|
||||||
|
let
|
||||||
|
( pageModel, pageCmd, contextCmd ) =
|
||||||
|
config.page.update
|
||||||
|
{ route = config.toRoute model.url
|
||||||
|
, flags = model.flags
|
||||||
|
, context = model.context
|
||||||
|
}
|
||||||
|
msg_
|
||||||
|
(unwrap model.page)
|
||||||
|
in
|
||||||
|
( { model | page = map (always pageModel) model.page }
|
||||||
|
, Cmd.batch
|
||||||
|
[ Cmd.map ContextMsg contextCmd
|
||||||
|
, Cmd.map PageMsg pageCmd
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Document msg =
|
||||||
|
{ title : String
|
||||||
|
, body : List (Html msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
view :
|
||||||
|
Config flags route contextModel contextMsg model msg
|
||||||
|
-> Model flags contextModel model
|
||||||
|
-> Document (Msg contextMsg msg)
|
||||||
|
view config model =
|
||||||
|
let
|
||||||
|
transitionProp : Float -> String
|
||||||
|
transitionProp ms =
|
||||||
|
"opacity " ++ String.fromFloat ms ++ "ms ease-in-out"
|
||||||
|
|
||||||
|
layoutOpacity : Loadable a -> String
|
||||||
|
layoutOpacity loadable =
|
||||||
|
case loadable of
|
||||||
|
FirstLoad _ ->
|
||||||
|
"0"
|
||||||
|
|
||||||
|
Loading _ ->
|
||||||
|
"1"
|
||||||
|
|
||||||
|
Loaded _ ->
|
||||||
|
"1"
|
||||||
|
|
||||||
|
pageOpacity : Loadable a -> String
|
||||||
|
pageOpacity loadable =
|
||||||
|
case loadable of
|
||||||
|
FirstLoad _ ->
|
||||||
|
"0"
|
||||||
|
|
||||||
|
Loading _ ->
|
||||||
|
"0"
|
||||||
|
|
||||||
|
Loaded _ ->
|
||||||
|
"1"
|
||||||
|
in
|
||||||
|
{ title = config.title (config.toRoute model.url)
|
||||||
|
, body =
|
||||||
|
[ div
|
||||||
|
[ Attr.style "transition" (transitionProp config.transition)
|
||||||
|
, Attr.style "opacity" (layoutOpacity model.page)
|
||||||
|
]
|
||||||
|
[ config.context.view
|
||||||
|
{ route = config.toRoute model.url
|
||||||
|
, toMsg = ContextMsg
|
||||||
|
, context = model.context
|
||||||
|
, viewPage =
|
||||||
|
div
|
||||||
|
[ Attr.style "transition" (transitionProp config.transition)
|
||||||
|
, 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)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
subscriptions :
|
||||||
|
Config flags route contextModel contextMsg model msg
|
||||||
|
-> Model flags contextModel model
|
||||||
|
-> Sub (Msg contextMsg msg)
|
||||||
|
subscriptions config model =
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
]
|
185
src/Application/Page.elm
Normal file
185
src/Application/Page.elm
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
module Application.Page exposing
|
||||||
|
( Context
|
||||||
|
, Page
|
||||||
|
, element
|
||||||
|
, init
|
||||||
|
, page
|
||||||
|
, sandbox
|
||||||
|
, static
|
||||||
|
, subscriptions
|
||||||
|
, update
|
||||||
|
, view
|
||||||
|
)
|
||||||
|
|
||||||
|
import Html exposing (Html)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Context flags route contextModel =
|
||||||
|
{ flags : flags
|
||||||
|
, route : route
|
||||||
|
, context : contextModel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Page route flags contextModel contextMsg model msg appModel appMsg =
|
||||||
|
{ 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
|
||||||
|
, toModel : model -> appModel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- PAGE HELPERS
|
||||||
|
|
||||||
|
|
||||||
|
init :
|
||||||
|
{ page : Page route flags contextModel contextMsg model msg appModel appMsg
|
||||||
|
}
|
||||||
|
-> Context flags route contextModel
|
||||||
|
-> ( appModel, Cmd appMsg, Cmd contextMsg )
|
||||||
|
init config context =
|
||||||
|
config.page.init context
|
||||||
|
|> mapTruple
|
||||||
|
{ fromMsg = config.page.toMsg
|
||||||
|
, fromModel = config.page.toModel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update :
|
||||||
|
{ page : Page route flags contextModel contextMsg model msg appModel appMsg
|
||||||
|
, msg : msg
|
||||||
|
, model : model
|
||||||
|
}
|
||||||
|
-> Context flags route contextModel
|
||||||
|
-> ( appModel, Cmd appMsg, Cmd contextMsg )
|
||||||
|
update config context =
|
||||||
|
config.page.update 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
|
||||||
|
}
|
||||||
|
-> Context flags route contextModel
|
||||||
|
-> Sub appMsg
|
||||||
|
subscriptions config context =
|
||||||
|
config.page.subscriptions context config.model
|
||||||
|
|> Sub.map config.page.toMsg
|
||||||
|
|
||||||
|
|
||||||
|
view :
|
||||||
|
{ page : Page route flags contextModel contextMsg model msg appModel appMsg
|
||||||
|
, model : model
|
||||||
|
}
|
||||||
|
-> Context flags route contextModel
|
||||||
|
-> Html appMsg
|
||||||
|
view config context =
|
||||||
|
config.page.view context config.model
|
||||||
|
|> Html.map config.page.toMsg
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- PAGE ADAPTERS
|
||||||
|
|
||||||
|
|
||||||
|
static :
|
||||||
|
{ view : Html Never
|
||||||
|
, toModel : () -> appModel
|
||||||
|
}
|
||||||
|
-> Page route flags contextModel contextMsg () Never appModel appMsg
|
||||||
|
static config =
|
||||||
|
{ 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
|
||||||
|
, toMsg = never
|
||||||
|
, toModel = config.toModel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sandbox :
|
||||||
|
{ init : model
|
||||||
|
, update : msg -> model -> model
|
||||||
|
, view : model -> Html msg
|
||||||
|
, toMsg : msg -> appMsg
|
||||||
|
, toModel : model -> appModel
|
||||||
|
}
|
||||||
|
-> Page route flags contextModel contextMsg model msg appModel appMsg
|
||||||
|
sandbox config =
|
||||||
|
{ 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
|
||||||
|
, toMsg = config.toMsg
|
||||||
|
, toModel = config.toModel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
element :
|
||||||
|
{ init : flags -> ( model, Cmd msg )
|
||||||
|
, update : msg -> model -> ( model, Cmd msg )
|
||||||
|
, subscriptions : model -> Sub msg
|
||||||
|
, view : model -> Html msg
|
||||||
|
, toMsg : msg -> appMsg
|
||||||
|
, toModel : model -> appModel
|
||||||
|
}
|
||||||
|
-> Page route flags contextModel contextMsg model msg appModel appMsg
|
||||||
|
element config =
|
||||||
|
let
|
||||||
|
appendCmd ( model, cmd ) =
|
||||||
|
( model, cmd, Cmd.none )
|
||||||
|
in
|
||||||
|
{ 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
|
||||||
|
, toMsg = config.toMsg
|
||||||
|
, toModel = config.toModel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
page :
|
||||||
|
{ init : Context flags route contextModel -> ( model, Cmd msg )
|
||||||
|
, update : Context flags route contextModel -> msg -> model -> ( model, Cmd msg )
|
||||||
|
, subscriptions : Context flags route contextModel -> model -> Sub msg
|
||||||
|
, view : Context flags route contextModel -> model -> Html msg
|
||||||
|
, toMsg : msg -> appMsg
|
||||||
|
, toModel : model -> appModel
|
||||||
|
}
|
||||||
|
-> Page route flags contextModel contextMsg model msg appModel appMsg
|
||||||
|
page config =
|
||||||
|
let
|
||||||
|
appendCmd ( model, cmd ) =
|
||||||
|
( model, cmd, Cmd.none )
|
||||||
|
in
|
||||||
|
{ init = \c -> config.init c |> appendCmd
|
||||||
|
, update = \c msg model -> config.update c msg model |> appendCmd
|
||||||
|
, subscriptions = \c model -> config.subscriptions c model
|
||||||
|
, view = \c model -> config.view c model
|
||||||
|
, toMsg = config.toMsg
|
||||||
|
, toModel = config.toModel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- UTILS
|
||||||
|
|
||||||
|
|
||||||
|
mapTruple :
|
||||||
|
{ fromMsg : msg -> appMsg
|
||||||
|
, fromModel : model -> appModel
|
||||||
|
}
|
||||||
|
-> ( model, Cmd msg, Cmd contextMsg )
|
||||||
|
-> ( appModel, Cmd appMsg, Cmd contextMsg )
|
||||||
|
mapTruple { fromModel, fromMsg } ( a, b, c ) =
|
||||||
|
( fromModel a
|
||||||
|
, Cmd.map fromMsg b
|
||||||
|
, c
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user