diff --git a/README.md b/README.md index 39b0496..16526c2 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,12 @@ make serve Now open `http://localhost:8000` in your browser. -# Viewing - -Open index.html in your browser. - # TODO - [x] Add Makefile + - [ ] Determine if `src/Body.elm` or pages in `sr/Page` should have subscription functions + - [ ] use actix backend that maps most root requests to serve `actix_file::Files` + - [ ] Submit to slack for feedback... - [ ] Refactor into router page - [ ] Handle back-navigation - [ ] Add `default.nix` diff --git a/src/Body.elm b/src/Body.elm new file mode 100644 index 0000000..a88b20e --- /dev/null +++ b/src/Body.elm @@ -0,0 +1,66 @@ +module Body exposing (Msg(..), Model(..), init, update, view) + +import Element + +import Page.About +import Page.Contact +import Page.Landing +import Page.Products +import Page.Resources + +type Msg + = MsgLanding Page.Landing.Msg + | MsgProducts Page.Products.Msg + | MsgResources Page.Resources.Msg + | MsgAbout Page.About.Msg + | MsgContact Page.Contact.Msg + +type Model + = ModelLanding Page.Landing.Model + | ModelProducts Page.Products.Model + | ModelResources Page.Resources.Model + | ModelAbout Page.About.Model + | ModelContact Page.Contact.Model + +init : () -> Model +init flags = ModelLanding (Page.Landing.init flags) + +update : Msg -> Model -> (Model, Cmd Msg) +update bodyMsg bodyModel = + let + updatePage msg model updateFn wrapMsg toBodyModel = + let + (newModel, cmd) = updateFn msg model + in + (toBodyModel newModel, Cmd.map wrapMsg cmd) + in + case (bodyMsg, bodyModel) of + (MsgLanding msg, ModelLanding m) -> + updatePage msg m Page.Landing.update MsgLanding ModelLanding + + (MsgProducts msg, ModelProducts m) -> + updatePage msg m Page.Products.update MsgProducts ModelProducts + + (MsgResources msg, ModelResources m) -> + updatePage msg m Page.Resources.update MsgResources ModelResources + + (MsgAbout msg, ModelAbout m) -> + updatePage msg m Page.About.update MsgAbout ModelAbout + + (MsgContact msg, ModelContact m) -> + updatePage msg m Page.Contact.update MsgContact ModelContact + + _ -> + (bodyModel, Cmd.none) + +view : Model -> Element.Element Msg +view model = + let + content = case model of + ModelLanding m -> Page.Landing.view m |> Element.map MsgLanding + ModelProducts m -> Page.Products.view m |> Element.map MsgProducts + ModelResources m -> Page.Resources.view m |> Element.map MsgResources + ModelAbout m -> Page.About.view m |> Element.map MsgAbout + ModelContact m -> Page.Contact.view m |> Element.map MsgContact + in + Element.el [Element.centerY ,Element.centerX] content diff --git a/src/Header.elm b/src/Header.elm index 9f62398..4f7dd33 100644 --- a/src/Header.elm +++ b/src/Header.elm @@ -1,18 +1,17 @@ -module Header exposing (Model, Msg(..), view, init) +module Header exposing (Model, Msg, view, init, update) import Element exposing (Element) import Element.Events import Element.Border type alias Model = {} -type Msg - = ClickedProducts - | ClickedResources - | ClickedAbout - | ClickedContact +type alias Msg = {} init : () -> Model init flags = {} +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = (model, Cmd.none) + view : Model -> Element Msg view model = let diff --git a/src/Main.elm b/src/Main.elm index d35bd76..aaedc4b 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -1,35 +1,35 @@ module Main exposing (main) +-- external imports import Browser import Url import Html exposing (Html) import Element exposing (Element, el, text, column) import String exposing (right) import Browser.Navigation - -import Page.Landing -import Header +import Browser exposing (UrlRequest) import Html exposing (header) +-- internal imports +import Body +import Header --- MODEL -type Page - = Landing Page.Landing.Model - | Products - | Resources - | About - | Contact +type Msg + = Header Header.Msg + | Body Body.Msg + | UrlChanged Url.Url + | UrlRequest Browser.UrlRequest type alias Model = { key : Browser.Navigation.Key , url : Url.Url - , page : Page + , page : Body.Model , header : Header.Model} init : () -> Url.Url -> Browser.Navigation.Key -> ( Model, Cmd Msg ) init flags url key = let - page = Landing (Page.Landing.init flags) + page = Body.init flags header = Header.init flags model = { key = key @@ -40,85 +40,49 @@ init flags url key = in (model, Cmd.none) -toPage : Header.Msg -> Page -toPage msg = - case msg of - Header.ClickedProducts -> Products - Header.ClickedResources -> Resources - Header.ClickedAbout -> About - Header.ClickedContact -> Contact - --- TODO : move this function to Router.elm -toUrl : Url.Url -> Header.Msg -> Url.Url -toUrl baseUrl msg = - case msg of - Header.ClickedProducts -> {baseUrl | path = "/products"} - Header.ClickedResources -> {baseUrl | path = "/resources"} - Header.ClickedAbout -> {baseUrl | path = "/about"} - Header.ClickedContact -> {baseUrl | path = "/contact"} - --- UPDATE -type Msg - = NoOp - | Header Header.Msg - | LandingPage Page.Landing.Msg - | UrlChanged Url.Url - | UrlRequest Browser.UrlRequest - - update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of - Header headerMsg -> + Body bodyMsg -> let - newUrl = toUrl model.url headerMsg - newModel = { model | page = toPage headerMsg } + (newPage, cmd) = Body.update bodyMsg model.page in - (newModel, Browser.Navigation.pushUrl model.key (Url.toString newUrl)) - UrlChanged url -> - (model, Browser.Navigation.pushUrl model.key (Url.toString url)) + ( {model | page = newPage}, cmd |> Cmd.map Body ) + UrlChanged url -> + ( {model | url = url}, Cmd.none ) + UrlRequest (Browser.Internal url) -> + ( model, Browser.Navigation.pushUrl model.key (Url.toString url) ) _ -> (model, Cmd.none) subscriptions : Model -> Sub Msg subscriptions _ = Sub.none -viewBody : Model -> Element.Element Msg -viewBody model = - let - content = case model.page of - Landing m -> Page.Landing.view m |> Element.map LandingPage - Products -> Element.text "Products" - Resources -> Element.text "Resources" - About -> Element.text "About" - Contact -> Element.text "Contact" - in - Element.el [Element.centerY ,Element.centerX] content - --- VIEW view : Model -> Browser.Document Msg view model = let + header = Header.view model.header |> Element.map Header + body = Body.view model.page |> Element.map Body page = Element.column [ Element.width Element.fill , Element.height Element.fill , Element.centerX] - [ Header.view model.header |> Element.map Header - , viewBody model] + [ header + , body] in { title = "Example Spa Elm App" , body = [ Element.layout [] page ]} --- MAIN - main = Browser.application { - init = init - ,view = view - ,update = update - ,subscriptions = subscriptions - ,onUrlChange = UrlChanged - ,onUrlRequest = UrlRequest + init = init + ,view = view + ,update = update + ,subscriptions = subscriptions + -- when a link is clicked, first UrlRequest is issued + ,onUrlRequest = UrlRequest + -- then UrlChanged is issued + ,onUrlChange = UrlChanged } diff --git a/src/Page/About.elm b/src/Page/About.elm new file mode 100644 index 0000000..92c02a8 --- /dev/null +++ b/src/Page/About.elm @@ -0,0 +1,16 @@ +module Page.About exposing (Model, Msg, view, init, update) +import Element exposing (Element) + +type alias Model = {} +type alias Msg = {} + +init : () -> Model +init flags = {} + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = (model, Cmd.none) + +view : Model -> Element Msg +view model = + Element.el [] + <| Element.text "About" diff --git a/src/Page/Contact.elm b/src/Page/Contact.elm new file mode 100644 index 0000000..3000024 --- /dev/null +++ b/src/Page/Contact.elm @@ -0,0 +1,16 @@ +module Page.Contact exposing (Model, Msg, view, init, update) +import Element exposing (Element) + +type alias Model = {} +type alias Msg = {} + +init : () -> Model +init flags = {} + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = (model, Cmd.none) + +view : Model -> Element Msg +view model = + Element.el [] + <| Element.text "Contact" diff --git a/src/Page/Landing.elm b/src/Page/Landing.elm index 3767af0..3201232 100644 --- a/src/Page/Landing.elm +++ b/src/Page/Landing.elm @@ -1,4 +1,4 @@ -module Page.Landing exposing (Model, Msg, view, init) +module Page.Landing exposing (Model, Msg, view, init, update) import Element exposing (Element) type alias Model = {} @@ -7,6 +7,9 @@ type alias Msg = {} init : () -> Model init flags = {} +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = (model, Cmd.none) + view : Model -> Element Msg view model = Element.el [] diff --git a/src/Page/Products.elm b/src/Page/Products.elm new file mode 100644 index 0000000..125f98e --- /dev/null +++ b/src/Page/Products.elm @@ -0,0 +1,16 @@ +module Page.Products exposing (Model, Msg, view, init, update) +import Element exposing (Element) + +type alias Model = {} +type alias Msg = {} + +init : () -> Model +init flags = {} + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = (model, Cmd.none) + +view : Model -> Element Msg +view model = + Element.el [] + <| Element.text "Products" diff --git a/src/Page/Resources.elm b/src/Page/Resources.elm new file mode 100644 index 0000000..2a7272c --- /dev/null +++ b/src/Page/Resources.elm @@ -0,0 +1,16 @@ +module Page.Resources exposing (Model, Msg, view, init, update) +import Element exposing (Element) + +type alias Model = {} +type alias Msg = {} + +init : () -> Model +init flags = {} + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = (model, Cmd.none) + +view : Model -> Element Msg +view model = + Element.el [] + <| Element.text "Resources"