begin work on layouts

This commit is contained in:
Ryan Haskell-Glatz 2021-08-04 04:45:13 -05:00
parent afb3df6792
commit 6b280b4a6f
20 changed files with 1120 additions and 21 deletions

5
examples/08-layouts/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.DS_Store
.elm-spa
elm-stuff
node_modules
dist

View File

@ -0,0 +1,28 @@
# my new project
> 🌳 built with [elm-spa](https://elm-spa.dev)
## dependencies
This project requires the latest LTS version of [Node.js](https://nodejs.org/)
```bash
npm install -g elm elm-spa
```
## running locally
```bash
elm-spa server # starts this app at http:/localhost:1234
```
### other commands
```bash
elm-spa add # add a new page to the application
elm-spa build # production build
elm-spa watch # runs build as you code (without the server)
```
## learn more
You can learn more at [elm-spa.dev](https://elm-spa.dev)

View File

@ -0,0 +1,28 @@
{
"type": "application",
"source-directories": [
"src",
".elm-spa/defaults",
".elm-spa/generated",
"../../src"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/json": "1.1.3",
"elm/url": "1.0.0",
"elm-community/list-extra": "8.3.1"
},
"indirect": {
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.2"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://nope.rhg.dev/dist/3.0.0/core.min.css">
<style>
.h1 { font-weight: bold; font-size: 2rem }
.h3 { font-weight: bold; font-size: 1.25rem }
.h4 { font-weight: bold; }
a { text-decoration: underline;}
a, button { cursor: pointer;}
.border-right { border-right: solid 1px #ddd;}
</style>
</head>
<body>
<script src="/dist/elm.js"></script>
<script> Elm.Main.init() </script>
</body>
</html>

View File

@ -0,0 +1,118 @@
module Gen.Layout exposing
( Layout, static, sandbox
, Bundle, toBundle
--, element, advanced
)
{-|
@docs Layout, static, sandbox, element, advanced
@docs Bundle, toBundle
-}
import Effect exposing (Effect)
import Request exposing (Request)
import Shared
import View exposing (View)
-- LAYOUT
type Layout model msg mainMsg
= Layout (Internals model msg mainMsg)
static : { view : { viewPage : View mainMsg } -> View mainMsg } -> Layout () msg mainMsg
static layout =
Layout
{ record =
{ init = ( (), Effect.none )
, update = \_ model -> ( model, Effect.none )
, view = \options _ -> layout.view { viewPage = options.viewPage }
, subscriptions = \_ -> Sub.none
}
}
sandbox :
{ init : model
, update : msg -> model -> model
, view : { viewPage : View mainMsg, toMainMsg : msg -> mainMsg } -> model -> View mainMsg
}
-> Layout model msg mainMsg
sandbox layout =
Layout
{ record =
{ init = ( layout.init, Effect.none )
, update = \msg model -> ( layout.update msg model, Effect.none )
, view = layout.view
, subscriptions = \_ -> Sub.none
}
}
-- BUNDLE
type alias Internals model msg mainMsg =
{ record : LayoutRecord model msg mainMsg
}
type alias LayoutRecord model msg mainMsg =
{ init : ( model, Effect msg )
, update : msg -> model -> ( model, Effect msg )
, subscriptions : model -> Sub msg
, view :
{ viewPage : View mainMsg
, toMainMsg : msg -> mainMsg
}
-> model
-> View mainMsg
}
type alias Bundle model msg genModel genMsg mainMsg =
{ init : Shared.Model -> Request -> ( genModel, Effect genMsg )
, update : msg -> model -> Shared.Model -> Request -> ( genModel, Effect genMsg )
, subscriptions : model -> Shared.Model -> Request -> Sub genMsg
, view : model -> { viewPage : View mainMsg, toMainMsg : genMsg -> mainMsg } -> Shared.Model -> Request -> View mainMsg
}
toBundle :
(model -> genModel)
-> (msg -> genMsg)
-> (Shared.Model -> Request -> Layout model msg mainMsg)
-> Bundle model msg genModel genMsg mainMsg
toBundle toModel toMsg toLayout =
let
toRecord shared req =
case toLayout shared req of
Layout { record } ->
record
in
{ init =
\shared req ->
(toRecord shared req).init
|> Tuple.mapBoth toModel (Effect.map toMsg)
, update =
\msg model shared req ->
(toRecord shared req).update msg model
|> Tuple.mapBoth toModel (Effect.map toMsg)
, subscriptions =
\model shared req ->
(toRecord shared req).subscriptions model
|> Sub.map toMsg
, view =
\model options shared req ->
(toRecord shared req).view
{ viewPage = options.viewPage
, toMainMsg = toMsg >> options.toMainMsg
}
model
}

View File

@ -0,0 +1,107 @@
module Gen.Layouts exposing
( Layout(..)
, Model, init
, Msg, update
, view
, subscriptions
)
{-|
@docs Layout
@docs Model, init
@docs Msg, update
@docs view
@docs subscriptions
-}
import Effect exposing (Effect)
import Gen.Layout
import Layouts.Sidebar
import Request exposing (Request)
import Shared
import View exposing (View)
type Layout
= Sidebar
-- BUNDLE
type alias Bundle model msg mainMsg =
{ init : Shared.Model -> Request -> ( Model, Effect Msg )
, update : msg -> model -> Shared.Model -> Request -> ( Model, Effect Msg )
, subscriptions : model -> Shared.Model -> Request -> Sub Msg
, view : model -> { viewPage : View mainMsg, toMainMsg : Msg -> mainMsg } -> Shared.Model -> Request -> View mainMsg
}
layouts :
{ sidebar : Bundle Layouts.Sidebar.Model Layouts.Sidebar.Msg mainMsg
}
layouts =
{ sidebar = Gen.Layout.toBundle Sidebar_Model Sidebar_Msg Layouts.Sidebar.layout
}
-- INIT
type Model
= Sidebar_Model Layouts.Sidebar.Model
init : Layout -> Shared.Model -> Request -> ( Model, Effect Msg )
init layout =
case layout of
Sidebar ->
layouts.sidebar.init
-- UPDATE
type Msg
= Sidebar_Msg Layouts.Sidebar.Msg
update : Msg -> Model -> Shared.Model -> Request -> ( Model, Effect Msg )
update msg_ model_ =
case ( msg_, model_ ) of
( Sidebar_Msg msg, Sidebar_Model model ) ->
layouts.sidebar.update msg model
-- _ ->
-- \_ _ -> ( model_, Effect.none )
-- SUBSCRIPTIONS
subscriptions : Model -> Shared.Model -> Request -> Sub Msg
subscriptions model_ =
case model_ of
Sidebar_Model model ->
layouts.sidebar.subscriptions model
-- VIEW
view :
Model
-> { viewPage : View mainMsg, toMainMsg : Msg -> mainMsg }
-> Shared.Model
-> Request
-> View mainMsg
view model_ =
case model_ of
Sidebar_Model model ->
layouts.sidebar.view model

View File

@ -0,0 +1,228 @@
module Gen.Pages_ exposing (Model, Msg, init, layout, subscriptions, update, view)
import Browser.Navigation exposing (Key)
import Effect exposing (Effect)
import ElmSpa.Page
import Gen.Layouts
import Gen.Model as Model
import Gen.Msg as Msg
import Gen.Params.Apps
import Gen.Params.Devices
import Gen.Params.Home_
import Gen.Params.NotFound
import Gen.Params.People
import Gen.Params.Settings.General
import Gen.Params.Settings.Profile
import Gen.Params.SignIn
import Gen.Route as Route exposing (Route)
import Page exposing (Page)
import Pages.Apps
import Pages.Devices
import Pages.Home_
import Pages.NotFound
import Pages.People
import Pages.Settings.General
import Pages.Settings.Profile
import Pages.SignIn
import Request exposing (Request)
import Shared
import Task
import Url exposing (Url)
import View exposing (View)
type alias Model =
Model.Model
type alias Msg =
Msg.Msg
init : Route -> Shared.Model -> Url -> Key -> ( Model, Effect Msg )
init route =
case route of
Route.Apps ->
pages.apps.init ()
Route.Devices ->
pages.devices.init ()
Route.Home_ ->
pages.home_.init ()
Route.People ->
pages.people.init ()
Route.SignIn ->
pages.signIn.init ()
Route.Settings__General ->
pages.settings__general.init ()
Route.Settings__Profile ->
pages.settings__profile.init ()
Route.NotFound ->
pages.notFound.init ()
update : Msg -> Model -> Shared.Model -> Url -> Key -> ( Model, Effect Msg )
update msg_ model_ =
case ( msg_, model_ ) of
_ ->
\_ _ _ -> ( model_, Effect.none )
view : Model -> Shared.Model -> Url -> Key -> View Msg
view model_ =
case model_ of
Model.Redirecting_ ->
\_ _ _ -> View.none
Model.Apps params ->
pages.apps.view params ()
Model.Devices params ->
pages.devices.view params ()
Model.Home_ params ->
pages.home_.view params ()
Model.People params ->
pages.people.view params ()
Model.SignIn params ->
pages.signIn.view params ()
Model.Settings__General params ->
pages.settings__general.view params ()
Model.Settings__Profile params ->
pages.settings__profile.view params ()
Model.NotFound params ->
pages.notFound.view params ()
subscriptions : Model -> Shared.Model -> Url -> Key -> Sub Msg
subscriptions model_ =
case model_ of
Model.Redirecting_ ->
\_ _ _ -> Sub.none
Model.Apps params ->
pages.apps.subscriptions params ()
Model.Devices params ->
pages.devices.subscriptions params ()
Model.Home_ params ->
pages.home_.subscriptions params ()
Model.People params ->
pages.people.subscriptions params ()
Model.SignIn params ->
pages.signIn.subscriptions params ()
Model.Settings__General params ->
pages.settings__general.subscriptions params ()
Model.Settings__Profile params ->
pages.settings__profile.subscriptions params ()
Model.NotFound params ->
pages.notFound.subscriptions params ()
-- INTERNALS
pages :
{ apps : Static Gen.Params.Apps.Params
, devices : Static Gen.Params.Devices.Params
, home_ : Static Gen.Params.Home_.Params
, people : Static Gen.Params.People.Params
, signIn : Static Gen.Params.SignIn.Params
, settings__general : Static Gen.Params.Settings.General.Params
, settings__profile : Static Gen.Params.Settings.Profile.Params
, notFound : Static Gen.Params.NotFound.Params
}
pages =
{ apps = static Pages.Apps.view Model.Apps
, devices = static Pages.Devices.view Model.Devices
, home_ = static Pages.Home_.view Model.Home_
, people = static Pages.People.view Model.People
, signIn = static Pages.SignIn.view Model.SignIn
, settings__general = static Pages.Settings.General.view Model.Settings__General
, settings__profile = static Pages.Settings.Profile.view Model.Settings__Profile
, notFound = static Pages.NotFound.view Model.NotFound
}
type alias Bundle params model msg =
ElmSpa.Page.Bundle params model msg Shared.Model (Effect Msg) Model Msg (View Msg)
bundle page toModel toMsg =
ElmSpa.Page.bundle
{ redirecting =
{ model = Model.Redirecting_
, view = View.none
}
, toRoute = Route.fromUrl
, toUrl = Route.toHref
, fromCmd = Effect.fromCmd
, mapEffect = Effect.map toMsg
, mapView = View.map toMsg
, toModel = toModel
, toMsg = toMsg
, page = page
}
type alias Static params =
Bundle params () Never
static : View Never -> (params -> Model) -> Static params
static view_ toModel =
{ init = \params _ _ _ -> ( toModel params, Effect.none )
, update = \params _ _ _ _ _ -> ( toModel params, Effect.none )
, view = \_ _ _ _ _ -> View.map never view_
, subscriptions = \_ _ _ _ _ -> Sub.none
}
-- LAYOUTS
layout : Route -> Maybe Gen.Layouts.Layout
layout route =
case route of
Route.Home_ ->
Just Pages.Home_.layout
Route.Apps ->
Just Pages.Apps.layout
Route.Devices ->
Just Pages.Devices.layout
Route.People ->
Just Pages.People.layout
Route.Settings__General ->
Just Pages.Settings.General.layout
Route.Settings__Profile ->
Just Pages.Settings.Profile.layout
Route.SignIn ->
Nothing
Route.NotFound ->
Nothing

View File

@ -0,0 +1,156 @@
module Layouts.Sidebar exposing (Model, Msg, layout)
import Gen.Layout exposing (Layout)
import Gen.Route as Route exposing (Route)
import Html exposing (Html)
import Html.Attributes as Attr
import Html.Events as Events
import List.Extra
import Request exposing (Request)
import Shared
import View exposing (View)
layout : Shared.Model -> Request -> Layout Model Msg mainMsg
layout shared req =
Gen.Layout.sandbox
{ init = init
, update = update
, view = view
}
-- INIT
type alias Model =
{ expandedSections : List Section
}
type Section
= SystemOfRecord
| Settings
init : Model
init =
{ expandedSections = []
}
-- UPDATE
type Msg
= Toggle Section
update : Msg -> Model -> Model
update msg model =
case msg of
Toggle section ->
let
expandedSections =
if List.member section model.expandedSections then
List.Extra.remove section model.expandedSections
else
section :: model.expandedSections
in
{ model | expandedSections = expandedSections }
-- VIEW
view :
{ viewPage : View mainMsg
, toMainMsg : Msg -> mainMsg
}
-> Model
-> View mainMsg
view { viewPage, toMainMsg } model =
{ title = viewPage.title
, body =
[ Html.div [ Attr.class "row align-top pad-xl gap-lg fill-y" ]
[ Html.map toMainMsg (viewSidebar model)
, Html.div [ Attr.class "page" ] viewPage.body
]
]
}
viewSidebar : Model -> Html Msg
viewSidebar model =
Html.aside [ Attr.class "col gap-xl fill-y border-right pad-right-lg" ]
[ Html.div [ Attr.class "col gap-md" ]
[ Html.a [ Attr.class "h3", Attr.href (Route.toHref Route.Home_) ] [ Html.text "Super App" ]
, Html.div [ Attr.class "col gap-md" ]
(List.map (viewSidebarSection model.expandedSections) [ SystemOfRecord, Settings ])
]
, viewSectionLink { label = "Sign out", route = Route.SignIn }
]
viewSidebarSection : List Section -> Section -> Html Msg
viewSidebarSection expandedSections section =
let
isExpanded =
List.member section expandedSections
viewExpandedItems =
if isExpanded then
Html.div [ Attr.class "col gap-sm pad-left-lg" ] (List.map viewSectionLink (sectionLinks section))
else
Html.text ""
icon =
if isExpanded then
" "
else
"👇 "
in
Html.section [ Attr.class "col gap-sm" ]
[ Html.button [ Attr.class "h4", Events.onClick (Toggle section) ] [ Html.text (icon ++ sectionName section) ]
, viewExpandedItems
]
viewSectionLink : { label : String, route : Route } -> Html msg
viewSectionLink { label, route } =
Html.a [ Attr.class "row h5", Attr.href (Route.toHref route) ] [ Html.text label ]
-- SECTION
sectionName : Section -> String
sectionName section =
case section of
SystemOfRecord ->
"System of record"
Settings ->
"Settings"
sectionLinks : Section -> List { label : String, route : Route }
sectionLinks section =
case section of
SystemOfRecord ->
[ { label = "Apps", route = Route.Apps }
, { label = "Devices", route = Route.Devices }
, { label = "People", route = Route.People }
]
Settings ->
[ { label = "General", route = Route.Settings__General }
, { label = "Profile", route = Route.Settings__Profile }
]

View File

@ -0,0 +1,244 @@
module Main exposing (main)
import Browser
import Browser.Navigation as Nav exposing (Key)
import Effect exposing (Effect)
import Gen.Layouts exposing (Layout)
import Gen.Model
import Gen.Pages_ as Pages
import Gen.Route as Route
import Request exposing (Request)
import Shared
import Url exposing (Url)
import View
main : Program Shared.Flags Model Msg
main =
Browser.application
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
, onUrlChange = ChangedUrl
, onUrlRequest = ClickedLink
}
-- INIT
type alias Model =
{ url : Url
, key : Key
, shared : Shared.Model
, layout : Maybe { kind : Layout, model : Gen.Layouts.Model }
, page : Pages.Model
}
init : Shared.Flags -> Url -> Key -> ( Model, Cmd Msg )
init flags url key =
let
req =
Request.create () url key
( shared, sharedCmd ) =
Shared.init req flags
( page, pageEffect ) =
Pages.init (Route.fromUrl url) shared url key
maybeLayout =
Pages.layout (Route.fromUrl url)
|> Maybe.map (initializeLayout { shared = shared, request = req })
in
( Model url key shared (Maybe.map toKindAndModel maybeLayout) page
, Cmd.batch
[ Cmd.map Shared sharedCmd
, Effect.toCmd ( Shared, Page ) pageEffect
, Effect.toCmd ( Shared, Layout ) (toLayoutEffect maybeLayout)
]
)
initializeLayout : { shared : Shared.Model, request : Request } -> Layout -> { kind : Layout, model : Gen.Layouts.Model, effect : Effect Gen.Layouts.Msg }
initializeLayout { shared, request } layoutKind =
let
( model, effect ) =
Gen.Layouts.init layoutKind shared request
in
{ kind = layoutKind
, model = model
, effect = effect
}
toKindAndModel : { a | kind : b, model : c } -> { kind : b, model : c }
toKindAndModel x =
{ kind = x.kind, model = x.model }
toLayoutEffect : Maybe { a | effect : Effect msg } -> Effect msg
toLayoutEffect maybeLayout =
maybeLayout
|> Maybe.map .effect
|> Maybe.withDefault Effect.none
-- UPDATE
type Msg
= ChangedUrl Url
| ClickedLink Browser.UrlRequest
| Shared Shared.Msg
| Layout Gen.Layouts.Msg
| Page Pages.Msg
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ClickedLink (Browser.Internal url) ->
( model
, Nav.pushUrl model.key (Url.toString url)
)
ClickedLink (Browser.External url) ->
( model
, Nav.load url
)
ChangedUrl url ->
if url.path /= model.url.path then
let
route =
Route.fromUrl url
( page, effect ) =
Pages.init route model.shared url model.key
currentLayout =
model.layout
newLayoutKind =
Pages.layout route
in
if Maybe.map .kind currentLayout == newLayoutKind then
( { model | url = url, page = page }
, Effect.toCmd ( Shared, Page ) effect
)
else
let
maybeLayout =
newLayoutKind
|> Maybe.map
(initializeLayout
{ shared = model.shared
, request = Request.create () url model.key
}
)
in
( { model
| url = url
, page = page
, layout = Maybe.map toKindAndModel maybeLayout
}
, Cmd.batch
[ Effect.toCmd ( Shared, Page ) effect
, Effect.toCmd ( Shared, Layout ) (toLayoutEffect maybeLayout)
]
)
else
( { model | url = url }, Cmd.none )
Shared sharedMsg ->
let
( shared, sharedCmd ) =
Shared.update (Request.create () model.url model.key) sharedMsg model.shared
( page, effect ) =
Pages.init (Route.fromUrl model.url) shared model.url model.key
in
if page == Gen.Model.Redirecting_ then
( { model | shared = shared, page = page }
, Cmd.batch
[ Cmd.map Shared sharedCmd
, Effect.toCmd ( Shared, Page ) effect
]
)
else
( { model | shared = shared }
, Cmd.map Shared sharedCmd
)
Page pageMsg ->
let
( page, effect ) =
Pages.update pageMsg model.page model.shared model.url model.key
in
( { model | page = page }
, Effect.toCmd ( Shared, Page ) effect
)
Layout layoutMsg ->
case model.layout of
Just layout ->
let
req =
Request.create () model.url model.key
( newLayoutModel, effect ) =
Gen.Layouts.update layoutMsg layout.model model.shared req
in
( { model | layout = Just { layout | model = newLayoutModel } }
, Effect.toCmd ( Shared, Layout ) effect
)
Nothing ->
( model, Cmd.none )
-- VIEW
view : Model -> Browser.Document Msg
view model =
let
viewPage =
Pages.view model.page model.shared model.url model.key
|> View.map Page
viewLayout =
case model.layout of
Just layout ->
Gen.Layouts.view layout.model
{ viewPage = viewPage
, toMainMsg = Layout
}
model.shared
(Request.create () model.url model.key)
Nothing ->
viewPage
in
View.toBrowserDocument viewLayout
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch
[ Pages.subscriptions model.page model.shared model.url model.key |> Sub.map Page
, Shared.subscriptions (Request.create () model.url model.key) model.shared |> Sub.map Shared
]

View File

@ -0,0 +1,14 @@
module Pages.Apps exposing (layout, view)
import Gen.Layouts
import View exposing (View)
layout : Gen.Layouts.Layout
layout =
Gen.Layouts.Sidebar
view : View msg
view =
View.placeholder "Apps"

View File

@ -0,0 +1,14 @@
module Pages.Devices exposing (layout, view)
import Gen.Layouts
import View exposing (View)
layout : Gen.Layouts.Layout
layout =
Gen.Layouts.Sidebar
view : View msg
view =
View.placeholder "Devices"

View File

@ -0,0 +1,14 @@
module Pages.Home_ exposing (layout, view)
import Gen.Layouts
import View exposing (View)
layout : Gen.Layouts.Layout
layout =
Gen.Layouts.Sidebar
view : View msg
view =
View.placeholder "Dashboard"

View File

@ -0,0 +1,14 @@
module Pages.People exposing (layout, view)
import Gen.Layouts
import View exposing (View)
layout : Gen.Layouts.Layout
layout =
Gen.Layouts.Sidebar
view : View msg
view =
View.placeholder "People"

View File

@ -0,0 +1,14 @@
module Pages.Settings.General exposing (layout, view)
import Gen.Layouts
import View exposing (View)
layout : Gen.Layouts.Layout
layout =
Gen.Layouts.Sidebar
view : View msg
view =
View.placeholder "Settings.General"

View File

@ -0,0 +1,14 @@
module Pages.Settings.Profile exposing (layout, view)
import Gen.Layouts
import View exposing (View)
layout : Gen.Layouts.Layout
layout =
Gen.Layouts.Sidebar
view : View msg
view =
View.placeholder "Settings.Profile"

View File

@ -0,0 +1,18 @@
module Pages.SignIn exposing (view)
import Gen.Route as Route
import Html
import Html.Attributes as Attr
import View exposing (View)
view : View msg
view =
{ title = "Sign in"
, body =
[ Html.div [ Attr.class "col center fill-y gap-lg" ]
[ Html.h1 [ Attr.class "h1" ] [ Html.text "Welcome back!" ]
, Html.a [ Attr.href (Route.toHref Route.Home_) ] [ Html.text "Sign in" ]
]
]
}

View File

@ -0,0 +1,24 @@
module Transition exposing (Transition, layout, page)
type alias Transition attr =
{ duration : Int
, invisible : List attr
, visible : List attr
}
layout : Transition attr
layout =
{ duration = 0
, invisible = []
, visible = []
}
page : Transition attr
page =
{ duration = 0
, invisible = []
, visible = []
}

View File

@ -0,0 +1,37 @@
module View exposing (View, map, none, placeholder, toBrowserDocument)
import Browser
import Html exposing (Html)
import Html.Attributes as Attr
type alias View msg =
{ title : String
, body : List (Html msg)
}
placeholder : String -> View msg
placeholder str =
{ title = str
, body = [ Html.h1 [ Attr.class "h1" ] [ Html.text str ] ]
}
none : View msg
none =
placeholder ""
map : (a -> b) -> View a -> View b
map fn view =
{ title = view.title
, body = List.map (Html.map fn) view.body
}
toBrowserDocument : View msg -> Browser.Document msg
toBrowserDocument view =
{ title = view.title
, body = view.body
}

View File

@ -63,7 +63,7 @@ static :
}
-> Page shared route effect view () msg
static none page =
Page (\_ _ -> Ok (adapters.static none page))
Page { toResult = \_ _ -> Ok (adapters.static none page) }
{-| A page that can keep track of application state.
@ -94,7 +94,7 @@ sandbox :
}
-> Page shared route effect view model msg
sandbox none page =
Page (\_ _ -> Ok (adapters.sandbox none page))
Page { toResult = \_ _ -> Ok (adapters.sandbox none page) }
{-| A page that can handle effects like [HTTP requests or subscriptions](https://guide.elm-lang.org/effects/).
@ -128,7 +128,7 @@ element :
}
-> Page shared route effect view model msg
element fromCmd page =
Page (\_ _ -> Ok (adapters.element fromCmd page))
Page { toResult = \_ _ -> Ok (adapters.element fromCmd page) }
{-| A page that can handles **custom** effects like sending a `Shared.Msg` or other general user-defined effects.
@ -159,7 +159,7 @@ advanced :
}
-> Page shared route effect view model msg
advanced page =
Page (\_ _ -> Ok (adapters.advanced page))
Page { toResult = \_ _ -> Ok (adapters.advanced page) }
{-| Actions to take when a user visits a `protected` page
@ -252,14 +252,15 @@ protected options =
let
protect toPage toRecord =
Page
(\shared req ->
case options.beforeInit shared req of
Provide user ->
Ok (user |> toRecord |> toPage)
{ toResult =
\shared req ->
case options.beforeInit shared req of
Provide user ->
Ok (user |> toRecord |> toPage)
RedirectTo route ->
Err route
)
RedirectTo route ->
Err route
}
in
{ static = protect (adapters.static options.effectNone)
, sandbox = protect (adapters.sandbox options.effectNone)
@ -366,10 +367,10 @@ toResult :
-> Result route (PageRecord effect view model msg)
toResult toPage shared req =
let
(Page toResult_) =
(Page page) =
toPage shared req
in
toResult_ shared (ElmSpa.Request.create req.route () req.url req.key)
page.toResult shared (ElmSpa.Request.create req.route () req.url req.key)
@ -377,7 +378,8 @@ toResult toPage shared req =
type alias Internals shared route effect view model msg =
shared -> Request route () -> Result route (PageRecord effect view model msg)
{ toResult : shared -> Request route () -> Result route (PageRecord effect view model msg)
}
type alias PageRecord effect view model msg =

View File

@ -3,8 +3,8 @@ module Main exposing (main)
import Browser
import Browser.Navigation as Nav exposing (Key)
import Effect
import Gen.Gen.Pages as Pages
import Gen.Model
import Gen.Pages as Pages
import Gen.Route as Route
import Request
import Shared
@ -43,7 +43,7 @@ init flags url key =
Shared.init (Request.create () url key) flags
( page, effect ) =
Pages.init (Route.fromUrl url) shared url key
Gen.Pages.init (Route.fromUrl url) shared url key
in
( Model url key shared page
, Cmd.batch
@ -81,7 +81,7 @@ update msg model =
if url.path /= model.url.path then
let
( page, effect ) =
Pages.init (Route.fromUrl url) model.shared url model.key
Gen.Pages.init (Route.fromUrl url) model.shared url model.key
in
( { model | url = url, page = page }
, Effect.toCmd ( Shared, Page ) effect
@ -96,7 +96,7 @@ update msg model =
Shared.update (Request.create () model.url model.key) sharedMsg model.shared
( page, effect ) =
Pages.init (Route.fromUrl model.url) shared model.url model.key
Gen.Pages.init (Route.fromUrl model.url) shared model.url model.key
in
if page == Gen.Model.Redirecting_ then
( { model | shared = shared, page = page }
@ -114,7 +114,7 @@ update msg model =
Page pageMsg ->
let
( page, effect ) =
Pages.update pageMsg model.page model.shared model.url model.key
Gen.Pages.update pageMsg model.page model.shared model.url model.key
in
( { model | page = page }
, Effect.toCmd ( Shared, Page ) effect
@ -127,7 +127,7 @@ update msg model =
view : Model -> Browser.Document Msg
view model =
Pages.view model.page model.shared model.url model.key
Gen.Pages.view model.page model.shared model.url model.key
|> View.map Page
|> View.toBrowserDocument
@ -139,6 +139,6 @@ view model =
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.batch
[ Pages.subscriptions model.page model.shared model.url model.key |> Sub.map Page
[ Gen.Pages.subscriptions model.page model.shared model.url model.key |> Sub.map Page
, Shared.subscriptions (Request.create () model.url model.key) model.shared |> Sub.map Shared
]