begin work on nested layouts

This commit is contained in:
Ryan Haskell-Glatz 2019-10-20 14:11:53 -05:00
parent b36bc7cf6e
commit 371765e9ac
15 changed files with 415 additions and 85 deletions

View File

@ -1,6 +1,7 @@
module Generated.Pages exposing (Model, Msg, bundle, init, update) module Generated.Pages exposing (Model, Msg, bundle, init, update)
import Application import Application
import Generated.Pages.Settings as Settings
import Generated.Route as Route exposing (Route) import Generated.Route as Route exposing (Route)
import Html exposing (Html) import Html exposing (Html)
import Pages.Counter as Counter import Pages.Counter as Counter
@ -16,6 +17,7 @@ type Model
| CounterModel Counter.Model | CounterModel Counter.Model
| RandomModel Random.Model | RandomModel Random.Model
| NotFoundModel NotFound.Model | NotFoundModel NotFound.Model
| SettingsModel Settings.Model
| Users_SlugModel Users_Slug.Model | Users_SlugModel Users_Slug.Model
| Users_Slug_Posts_SlugModel Users_Slug_Posts_Slug.Model | Users_Slug_Posts_SlugModel Users_Slug_Posts_Slug.Model
@ -24,6 +26,7 @@ type Msg
= HomepageMsg Homepage.Msg = HomepageMsg Homepage.Msg
| CounterMsg Counter.Msg | CounterMsg Counter.Msg
| RandomMsg Random.Msg | RandomMsg Random.Msg
| SettingsMsg Settings.Msg
| NotFoundMsg NotFound.Msg | NotFoundMsg NotFound.Msg
| Users_SlugMsg Users_Slug.Msg | Users_SlugMsg Users_Slug.Msg
| Users_Slug_Posts_SlugMsg Users_Slug_Posts_Slug.Msg | Users_Slug_Posts_SlugMsg Users_Slug_Posts_Slug.Msg
@ -53,6 +56,14 @@ random =
} }
settings : Application.Recipe Settings.Params Settings.Model Settings.Msg Model Msg
settings =
Settings.page
{ toModel = SettingsModel
, toMsg = SettingsMsg
}
notFound : Application.Recipe NotFound.Params NotFound.Model NotFound.Msg Model Msg notFound : Application.Recipe NotFound.Params NotFound.Model NotFound.Msg Model Msg
notFound = notFound =
NotFound.page NotFound.page
@ -89,6 +100,9 @@ init route =
Route.Random params -> Route.Random params ->
random.init params random.init params
Route.Settings params ->
settings.init params
Route.NotFound params -> Route.NotFound params ->
notFound.init params notFound.init params
@ -120,6 +134,12 @@ update appMsg appModel =
( RandomMsg _, _ ) -> ( RandomMsg _, _ ) ->
Application.keep appModel Application.keep appModel
( SettingsMsg msg, SettingsModel model ) ->
settings.update msg model
( SettingsMsg _, _ ) ->
Application.keep appModel
( NotFoundMsg msg, NotFoundModel model ) -> ( NotFoundMsg msg, NotFoundModel model ) ->
notFound.update msg model notFound.update msg model
@ -151,6 +171,9 @@ bundle appModel =
RandomModel model -> RandomModel model ->
random.bundle model random.bundle model
SettingsModel model ->
settings.bundle model
NotFoundModel model -> NotFoundModel model ->
notFound.bundle model notFound.bundle model

View File

@ -0,0 +1,121 @@
module Generated.Pages.Settings exposing (Model, Msg, Params, page)
import Application
import Generated.Route.Settings as Route exposing (Route)
import Html exposing (..)
import Layouts.Settings
import Pages.Settings.Account as Account
import Pages.Settings.Notifications as Notifications
import Pages.Settings.User as User
-- TODO : Export Application.layout or something for scaling this trash
type Model
= AccountModel Account.Model
| NotificationsModel Notifications.Model
| UserModel User.Model
type Msg
= AccountMsg Account.Msg
| NotificationsMsg Notifications.Msg
| UserMsg User.Msg
type alias Params =
Route
page : Application.Page Params Model Msg model msg
page =
Application.glue glue
glue : Application.Glue Route Model Msg
glue =
{ layout = Layouts.Settings.layout
, pages = pages
}
pages : Application.Pages Route Model Msg
pages =
{ init = init
, update = update
, bundle = bundle
}
account : Application.Recipe Account.Params Account.Model Account.Msg Model Msg
account =
Account.page
{ toModel = AccountModel
, toMsg = AccountMsg
}
notifications : Application.Recipe Notifications.Params Notifications.Model Notifications.Msg Model Msg
notifications =
Notifications.page
{ toModel = NotificationsModel
, toMsg = NotificationsMsg
}
user : Application.Recipe User.Params User.Model User.Msg Model Msg
user =
User.page
{ toModel = UserModel
, toMsg = UserMsg
}
init : Route -> ( Model, Cmd Msg )
init route =
case route of
Route.Account params ->
account.init params
Route.Notifications params ->
notifications.init params
Route.User params ->
user.init params
update : Msg -> Model -> ( Model, Cmd Msg )
update appMsg appModel =
case ( appMsg, appModel ) of
( AccountMsg msg, AccountModel model ) ->
account.update msg model
( AccountMsg _, _ ) ->
Application.keep appModel
( NotificationsMsg msg, NotificationsModel model ) ->
notifications.update msg model
( NotificationsMsg _, _ ) ->
Application.keep appModel
( UserMsg msg, UserModel model ) ->
user.update msg model
( UserMsg _, _ ) ->
Application.keep appModel
bundle : Model -> { view : Html Msg, subscriptions : Sub Msg }
bundle appModel =
case appModel of
AccountModel model ->
account.bundle model
NotificationsModel model ->
notifications.bundle model
UserModel model ->
user.bundle model

View File

@ -1,5 +1,6 @@
module Generated.Route exposing (Route(..), fromUrl, toPath) module Generated.Route exposing (Route(..), fromUrl, toPath)
import Generated.Route.Settings as Settings
import Url exposing (Url) import Url exposing (Url)
import Url.Parser as Parser exposing ((</>), Parser) import Url.Parser as Parser exposing ((</>), Parser)
@ -8,6 +9,7 @@ type Route
= Homepage () = Homepage ()
| Counter () | Counter ()
| Random () | Random ()
| Settings Settings.Route
| Users_Slug String | Users_Slug String
| Users_Slug_Posts_Slug UserPostInfo | Users_Slug_Posts_Slug UserPostInfo
| NotFound () | NotFound ()
@ -21,19 +23,20 @@ type alias UserPostInfo =
fromUrl : Url -> Route fromUrl : Url -> Route
fromUrl = fromUrl =
Parser.parse Parser.parse parser >> Maybe.withDefault (NotFound ())
(Parser.oneOf routes)
>> Maybe.withDefault (NotFound ())
routes : List (Parser (Route -> Route) Route) parser : Parser (Route -> a) a
routes = parser =
Parser.oneOf
[ Parser.top [ Parser.top
|> Parser.map (Homepage ()) |> Parser.map (Homepage ())
, Parser.s "counter" , Parser.s "counter"
|> Parser.map (Counter ()) |> Parser.map (Counter ())
, Parser.s "random" , Parser.s "random"
|> Parser.map (Random ()) |> Parser.map (Random ())
, Parser.s "settings"
|> (</>) (Parser.map Settings Settings.parser)
, (Parser.s "users" </> Parser.string) , (Parser.s "users" </> Parser.string)
|> Parser.map Users_Slug |> Parser.map Users_Slug
, (Parser.s "users" </> Parser.string </> Parser.s "posts" </> Parser.int) , (Parser.s "users" </> Parser.string </> Parser.s "posts" </> Parser.int)
@ -54,6 +57,9 @@ toPath route =
Random _ -> Random _ ->
"/random" "/random"
Settings r ->
"/settings" ++ Settings.toPath r
NotFound _ -> NotFound _ ->
"/not-found" "/not-found"

View File

@ -0,0 +1,38 @@
module Generated.Route.Settings exposing
( Route(..)
, parser
, toPath
)
import Url.Parser as Parser exposing ((</>), Parser)
type Route
= Account ()
| Notifications ()
| User ()
toPath : Route -> String
toPath route =
case route of
Account _ ->
"/account"
Notifications _ ->
"/notifications"
User _ ->
"/user"
parser : Parser (Route -> a) a
parser =
Parser.oneOf
[ Parser.s "account"
|> Parser.map (Account ())
, Parser.s "notifications"
|> Parser.map (Notifications ())
, Parser.s "user"
|> Parser.map (User ())
]

View File

@ -1,10 +1,17 @@
module Layout exposing (view) module Layouts.Main exposing (layout)
import Application
import Components.Navbar import Components.Navbar
import Html exposing (..) import Html exposing (..)
import Html.Attributes as Attr import Html.Attributes as Attr
layout : Application.Layout msg
layout =
{ view = view
}
view : { page : Html msg } -> Html msg view : { page : Html msg } -> Html msg
view { page } = view { page } =
div div

View File

@ -0,0 +1,18 @@
module Layouts.Settings exposing (layout)
import Application
import Html exposing (..)
layout : Application.Layout msg
layout =
{ view = view
}
view : { page : Html msg } -> Html msg
view { page } =
div []
[ h1 [] [ text "Settings" ]
, page
]

View File

@ -3,7 +3,7 @@ module Main exposing (main)
import Application exposing (Application) import Application exposing (Application)
import Generated.Pages as Pages import Generated.Pages as Pages
import Generated.Route as Route import Generated.Route as Route
import Layout as Layout import Layouts.Main
main : Application () Pages.Model Pages.Msg main : Application () Pages.Model Pages.Msg
@ -14,9 +14,7 @@ main =
, toPath = Route.toPath , toPath = Route.toPath
, transition = Application.fade 200 , transition = Application.fade 200
} }
, layout = , layout = Layouts.Main.layout
{ view = Layout.view
}
, pages = , pages =
{ init = Pages.init { init = Pages.init
, update = Pages.update , update = Pages.update

View File

@ -1,27 +0,0 @@
module Pages.Settings exposing (Model, Msg)
import Pages.Settings.Account as Account
import Pages.Settings.Notifications as Notifications
import Pages.Settings.User as User
-- TODO : Export Application.layout or something for scaling this trash
type Route
= Account
| Notifications
| User
type Model
= AccountModel Account.Model
| NotificationsModel Notifications.Model
| UserModel User.Model
type Msg
= AccountMsg Account.Msg
| NotificationsMsg Notifications.Msg
| UserMsg User.Msg

View File

@ -1,9 +1,33 @@
module Pages.Settings.Account exposing (Model, Msg) module Pages.Settings.Account exposing
( Model
, Msg
, Params
, page
)
import Application
import Html exposing (..)
type Model type alias Model =
= Model ()
type Msg type alias Msg =
= Msg Never
type alias Params =
()
page : Application.Page Params Model Msg model msg
page =
Application.static
{ view = view
}
view : Html Msg
view =
h3 [] [ text "Account" ]

View File

@ -1,9 +1,33 @@
module Pages.Settings.Notifications exposing (Model, Msg) module Pages.Settings.Notifications exposing
( Model
, Msg
, Params
, page
)
import Application
import Html exposing (..)
type Model type alias Model =
= Model ()
type Msg type alias Msg =
= Msg Never
type alias Params =
()
page : Application.Page Params Model Msg model msg
page =
Application.static
{ view = view
}
view : Html Msg
view =
h3 [] [ text "Notifications" ]

View File

@ -1,9 +1,33 @@
module Pages.Settings.User exposing (Model, Msg) module Pages.Settings.User exposing
( Model
, Msg
, Params
, page
)
import Application
import Html exposing (..)
type Model type alias Model =
= Model ()
type Msg type alias Msg =
= Msg Never
type alias Params =
()
page : Application.Page Params Model Msg model msg
page =
Application.static
{ view = view
}
view : Html Msg
view =
h3 [] [ text "User" ]

View File

@ -49,4 +49,6 @@ subscriptions model =
view : Model -> Html Msg view : Model -> Html Msg
view model = view model =
h1 [] [ text ("Post " ++ String.fromInt model.post ++ " for user: " ++ model.user) ] h1 []
[ text ("Post " ++ String.fromInt model.post ++ " for user: " ++ model.user)
]

View File

@ -1,18 +1,30 @@
module Application exposing module Application exposing
( Application, create ( Application, create
, Layout
, Page, Recipe , Page, Recipe
, Bundle, keep , Bundle, keep
, Static, static , Static, static
, Sandbox, sandbox , Sandbox, sandbox
, Element, element , Element, element
, Transition, fade , Glue, Pages, glue
, none , Transition, fade, none
) )
{-| {-|
## Applications
@docs Application, create @docs Application, create
## Layouts
@docs Layout
## Pages
@docs Page, Recipe @docs Page, Recipe
@docs Bundle, keep @docs Bundle, keep
@ -23,11 +35,12 @@ module Application exposing
@docs Element, element @docs Element, element
@docs PageWithParams, RecipeWithParams @docs Glue, Pages, glue
@docs ElementWithParams, elementWithParams
@docs Transition, fade ## Transitions
@docs Transition, fade, none
-} -}
@ -35,6 +48,7 @@ import Browser
import Browser.Dom as Dom import Browser.Dom as Dom
import Browser.Navigation as Nav import Browser.Navigation as Nav
import Html exposing (Html) import Html exposing (Html)
import Internals.Layout as Layout
import Internals.Page as Page import Internals.Page as Page
import Internals.Transition as Transition import Internals.Transition as Transition
import Internals.Transitionable as Transitionable exposing (Transitionable) import Internals.Transitionable as Transitionable exposing (Transitionable)
@ -93,7 +107,7 @@ create config =
, view = , view =
view view
{ view = config.pages.bundle >> .view { view = config.pages.bundle >> .view
, layout = config.layout.view , layout = config.layout
, transition = transition.strategy , transition = transition.strategy
} }
, onUrlChange = Url , onUrlChange = Url
@ -252,7 +266,7 @@ subscriptions config model =
view : view :
{ view : model -> Html msg { view : model -> Html msg
, transition : Transition.Strategy (Html msg) , transition : Transition.Strategy (Html msg)
, layout : { page : Html msg } -> Html msg , layout : Layout msg
} }
-> Model flags model -> Model flags model
-> Browser.Document (Msg msg) -> Browser.Document (Msg msg)
@ -263,19 +277,19 @@ view config model =
case model.page of case model.page of
Transitionable.Ready page -> Transitionable.Ready page ->
config.transition.beforeLoad config.transition.beforeLoad
{ layout = config.layout { layout = config.layout.view
, page = config.view page , page = config.view page
} }
Transitionable.Transitioning page -> Transitionable.Transitioning page ->
config.transition.leavingPage config.transition.leavingPage
{ layout = config.layout { layout = config.layout.view
, page = config.view page , page = config.view page
} }
Transitionable.Complete page -> Transitionable.Complete page ->
config.transition.enteringPage config.transition.enteringPage
{ layout = config.layout { layout = config.layout.view
, page = config.view page , page = config.view page
} }
] ]
@ -286,6 +300,10 @@ view config model =
-- PAGE API -- PAGE API
type alias Layout msg =
Layout.Layout msg
type alias Page params pageModel pageMsg model msg = type alias Page params pageModel pageMsg model msg =
Page.Page params pageModel pageMsg model msg Page.Page params pageModel pageMsg model msg
@ -314,28 +332,43 @@ static =
Page.static Page.static
type alias Sandbox pageModel pageMsg params = type alias Sandbox params pageModel pageMsg =
Page.Sandbox pageModel pageMsg params Page.Sandbox params pageModel pageMsg
sandbox : sandbox :
Sandbox pageModel pageMsg params Sandbox params pageModel pageMsg
-> Page params pageModel pageMsg model msg -> Page params pageModel pageMsg model msg
sandbox = sandbox =
Page.sandbox Page.sandbox
type alias Element pageModel pageMsg params = type alias Element params pageModel pageMsg =
Page.Element pageModel pageMsg params Page.Element params pageModel pageMsg
element : element :
Element pageModel pageMsg params Element params pageModel pageMsg
-> Page params pageModel pageMsg model msg -> Page params pageModel pageMsg model msg
element = element =
Page.element Page.element
type alias Glue route layoutModel layoutMsg =
Page.Glue route layoutModel layoutMsg
type alias Pages route layoutModel layoutMsg =
Page.Pages route layoutModel layoutMsg
glue :
Glue route layoutModel layoutMsg
-> Page params layoutModel layoutMsg model msg
glue =
Page.glue
-- TRANSITIONS -- TRANSITIONS

8
src/Internals/Layout.elm Normal file
View File

@ -0,0 +1,8 @@
module Internals.Layout exposing (Layout)
import Html exposing (Html)
type alias Layout msg =
{ view : { page : Html msg } -> Html msg
}

View File

@ -4,6 +4,7 @@ module Internals.Page exposing
, Static, static , Static, static
, Sandbox, sandbox , Sandbox, sandbox
, Element, element , Element, element
, Glue, Pages, glue
) )
{-| {-|
@ -18,9 +19,12 @@ module Internals.Page exposing
@docs Element, element @docs Element, element
@docs Glue, Pages, glue
-} -}
import Html exposing (Html) import Html exposing (Html)
import Internals.Layout exposing (Layout)
type alias Page params pageModel pageMsg model msg = type alias Page params pageModel pageMsg model msg =
@ -70,7 +74,7 @@ static page { toModel, toMsg } =
-- SANDBOX -- SANDBOX
type alias Sandbox pageModel pageMsg params = type alias Sandbox params pageModel pageMsg =
{ init : params -> pageModel { init : params -> pageModel
, update : pageMsg -> pageModel -> pageModel , update : pageMsg -> pageModel -> pageModel
, view : pageModel -> Html pageMsg , view : pageModel -> Html pageMsg
@ -78,7 +82,7 @@ type alias Sandbox pageModel pageMsg params =
sandbox : sandbox :
Sandbox pageModel pageMsg params Sandbox params pageModel pageMsg
-> Page params pageModel pageMsg model msg -> Page params pageModel pageMsg model msg
sandbox page { toModel, toMsg } = sandbox page { toModel, toMsg } =
{ init = \params -> ( toModel (page.init params), Cmd.none ) { init = \params -> ( toModel (page.init params), Cmd.none )
@ -99,7 +103,7 @@ sandbox page { toModel, toMsg } =
-- ELEMENT -- ELEMENT
type alias Element pageModel pageMsg params = type alias Element params pageModel pageMsg =
{ init : params -> ( pageModel, Cmd pageMsg ) { init : params -> ( pageModel, Cmd pageMsg )
, update : pageMsg -> pageModel -> ( pageModel, Cmd pageMsg ) , update : pageMsg -> pageModel -> ( pageModel, Cmd pageMsg )
, view : pageModel -> Html pageMsg , view : pageModel -> Html pageMsg
@ -108,7 +112,7 @@ type alias Element pageModel pageMsg params =
element : element :
Element pageModel pageMsg params Element params pageModel pageMsg
-> Page params pageModel pageMsg model msg -> Page params pageModel pageMsg model msg
element page { toModel, toMsg } = element page { toModel, toMsg } =
{ init = { init =
@ -123,3 +127,30 @@ element page { toModel, toMsg } =
, subscriptions = Sub.none , subscriptions = Sub.none
} }
} }
-- LAYOUT
type alias Glue route model msg =
{ layout : Layout msg
, pages : Pages route model msg
}
type alias Pages route model msg =
{ init : route -> ( model, Cmd msg )
, update : msg -> model -> ( model, Cmd msg )
, bundle : model -> Bundle msg
}
glue :
Glue route layoutModel layoutMsg
-> Page params layoutModel layoutMsg model msg
glue options { toModel, toMsg } =
{ init = Debug.todo "glue.init"
, update = Debug.todo "glue.update"
, bundle = Debug.todo "glue.bundle"
}