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 Browser exposing (UrlRequest) import Html exposing (header) import Ports -- internal imports import Body import Header 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 : Body.Model , header : Header.Model} init : () -> Url.Url -> Browser.Navigation.Key -> ( Model, Cmd Msg ) init flags url key = let page = Body.init flags header = Header.init flags model = { key = key , url = url , page = Body.handleRoute url.path , header = header } in (model, Ports.socketOpen) update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of Body bodyMsg -> let (newPage, cmd) = Body.update bodyMsg model.page in ( {model | page = newPage}, cmd |> Cmd.map Body ) UrlChanged url -> let newModel = {model | page = Body.handleRoute url.path, url = url} in ( newModel, Cmd.none ) UrlRequest (Browser.Internal url) -> ( model, Browser.Navigation.pushUrl model.key (Url.toString url) ) _ -> (model, Cmd.none) subscriptions : Model -> Sub Msg subscriptions model = Sub.batch [ model.header |> Header.subscriptions |> Sub.map Header , model.page |> Body.subscriptions |> Sub.map Body ] 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 , body] in { title = "Example Spa Elm App" , body = [ Element.layout [] page ]} main = Browser.application { 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 }