I think we've now hit what one might consider to be a good baseline

This commit is contained in:
Yehowshua Immanuel 2024-12-30 18:04:52 -05:00
parent 36d22a6f1c
commit 38bfd3bf18
9 changed files with 173 additions and 78 deletions

View file

@ -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`

66
src/Body.elm Normal file
View file

@ -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

View file

@ -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

View file

@ -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
}

16
src/Page/About.elm Normal file
View file

@ -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"

16
src/Page/Contact.elm Normal file
View file

@ -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"

View file

@ -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 []

16
src/Page/Products.elm Normal file
View file

@ -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"

16
src/Page/Resources.elm Normal file
View file

@ -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"