Switched to Elm / Suave

It's like F# on the client side - sweet!
This commit is contained in:
Daniel J. Summers
2016-12-11 19:39:06 -06:00
parent d3a80b9ceb
commit bde45c8554
45 changed files with 10698 additions and 1216 deletions

26
src/wwwroot/App.elm Normal file
View File

@@ -0,0 +1,26 @@
module App exposing (..)
import Messages exposing (..)
import Models exposing (Model, initialModel)
import Navigation exposing (Location)
import Routing exposing (Route(..), parseLocation)
import Update exposing (update)
import View exposing (view)
init : Location -> (Model, Cmd Msg)
init location =
let
currentRoute = Home --parseLocation location
in
(initialModel currentRoute, Cmd.none)
main : Program Never Model Msg
main =
Navigation.program OnLocationChange
{ init = init
, view = view
, update = update
, subscriptions = \_ -> Sub.none
}

View File

@@ -0,0 +1,19 @@
module Home.Public exposing (view)
import Html exposing (Html, p, text)
import Messages exposing (Msg(..))
import Models exposing (Model)
import Utils.View exposing (fullRow)
view : Model -> List (Html Msg)
view model =
let
paragraphs =
[ " "
, "myPrayerJournal is a place where individuals can record their prayer requests, record that they prayed for them, update them as God moves in the situation, and record a final answer received on that request. It will also allow individuals to review their answered prayers."
, "This site is currently in very limited alpha, as it is being developed with a core group of test users. If this is something you are interested in using, check back around mid-November 2016 to check on the development progress."
]
|> List.map (\para -> p [] [ text para ])
in
[ fullRow paragraphs ]

9
src/wwwroot/Messages.elm Normal file
View File

@@ -0,0 +1,9 @@
module Messages exposing (..)
import Navigation exposing (Location)
type Msg
= OnLocationChange Location
| NavTo String
| UpdateTitle String

16
src/wwwroot/Models.elm Normal file
View File

@@ -0,0 +1,16 @@
module Models exposing (..)
import Routing exposing (Route(..))
type alias Model =
{ route : Route
, title : String
}
initialModel : Route -> Model
initialModel route =
{ route = route
, title = "Index"
}

31
src/wwwroot/Routing.elm Normal file
View File

@@ -0,0 +1,31 @@
module Routing exposing (..)
import Navigation exposing (Location)
import UrlParser exposing (..)
type Route
= Home
| ChangePassword
| LogOff
| LogOn
| NotFound
findRoute : Parser (Route -> a) a
findRoute =
oneOf
[ map Home top
, map LogOn (s "user" </> s "log-on")
, map LogOff (s "user" </> s "log-off")
, map ChangePassword (s "user" </> s "password" </> s "change")
]
parseLocation : Location -> Route
parseLocation location =
case (parsePath findRoute location) of
Just route ->
route
Nothing ->
NotFound

21
src/wwwroot/Update.elm Normal file
View File

@@ -0,0 +1,21 @@
module Update exposing (..)
import Models exposing (Model)
import Messages exposing (Msg(..))
import Navigation exposing (newUrl)
import Routing exposing (parseLocation)
import Utils.View exposing (documentTitle)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
OnLocationChange location ->
let
newRoute = parseLocation location
in
({model | route = newRoute}, Cmd.none)
NavTo url ->
(model, newUrl url)
UpdateTitle newTitle ->
(model, documentTitle newTitle)

View File

@@ -0,0 +1,47 @@
port module Utils.View exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, href, style, title)
import Html.Events exposing (defaultOptions, onWithOptions)
import Json.Decode as Json
import Messages exposing (Msg(..))
-- Set the document title
port documentTitle : String -> Cmd a
-- Wrap the given content in a row
row : List (Html Msg) -> Html Msg
row columns =
div [ class "row "] columns
-- Display the given content in a full row
fullRow : List (Html Msg) -> Html Msg
fullRow content =
row
[ div
[ class "col-xs-12" ]
content
]
-- Create a navigation link
navLink : String -> String -> List (Attribute Msg) -> Html Msg
navLink url linkText attrs =
let
attributes =
List.concat
[
[ title linkText
, onWithOptions
"click" { defaultOptions | preventDefault = True }
<| Json.succeed
<| NavTo url
, href url
]
, attrs
]
in
a attributes [ text linkText ]

104
src/wwwroot/View.elm Normal file
View File

@@ -0,0 +1,104 @@
module View exposing (view)
import Html exposing (..)
import Html.Attributes exposing (attribute, class)
import Messages exposing (Msg(..))
import Models exposing (..)
import Routing exposing (Route(..))
import Utils.View exposing (documentTitle, navLink)
import Home.Public
-- Layout functions
navigation : List (Html Msg)
navigation =
[ navLink "/user/password/change" "Change Your Password" []
, navLink "/user/log-off" "Log Off" []
, navLink "/user/log-on" "Log On" []
]
|> List.map (\anchor -> li [] [ anchor ])
pageHeader : Html Msg
pageHeader =
div
[ class "navbar navbar-inverse navbar-fixed-top" ]
[ div
[ class "container" ]
[ div
[ class "navbar-header" ]
[ button
[ class "navbar-toggle"
, attribute "data-toggle" "collapse"
, attribute "data-target" ".navbar-collapse"
]
[ span [ class "sr-only" ] [ text "Toggle navigation" ]
, span [ class "icon-bar" ] []
, span [ class "icon-bar" ] []
, span [ class "icon-bar" ] []
]
, navLink "/" "myPrayerJournal" [ class "navbar-brand" ]
]
, div
[ class "navbar-collapse collapse" ]
[ ul
[ class "nav navbar-nav navbar-right" ]
navigation
]
]
]
pageTitle : String -> Html Msg
pageTitle title =
let
x = documentTitle <| title ++ " | myPrayerJournal"
in
h2 [ class "page-title" ] [ text title ]
pageFooter : Html Msg
pageFooter =
footer
[ class "mpj-footer" ]
[ p
[ class "text-right" ]
[ text "myPrayerJournal v0.8.1" ]
]
layout : Model -> String -> List (Html Msg) -> Html Msg
layout model pgTitle contents =
let
pageContent =
[ [ pageTitle pgTitle ]
, contents
, [ pageFooter ]
]
|> List.concat
in
div []
[ pageHeader
, div
[ class "container body-content" ]
pageContent
]
-- View functions
view : Model -> Html Msg
view model =
case model.route of
ChangePassword ->
layout model "Change Your Password" [ text "password change page goes here" ]
Home ->
layout model "Welcome" (Home.Public.view model)
LogOff ->
layout model "Log Off" [ text "Log off page goes hwere" ]
LogOn ->
layout model "Log On" [ text "Log On page goes here" ]
NotFound ->
layout model "Page Not Found" [ text "404, dude" ]

10330
src/wwwroot/app.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
body {
padding-top: 50px;
padding-bottom: 20px;
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
}
/* Wrapping element */
/* Set some basic padding to keep content from hitting the edges */
.body-content {
padding-left: 15px;
padding-right: 15px;
}
.material-icons.md-18 {
font-size: 18px;
}
.material-icons.md-24 {
font-size: 24px;
}
.material-icons.md-36 {
font-size: 36px;
}
.material-icons.md-48 {
font-size: 48px;
}
.material-icons {
vertical-align: middle;
}
.mpj-page-title {
border-bottom: solid 1px lightgray;
margin-bottom: 20px;
}
.mpj-footer {
border-top: solid 1px lightgray;
margin-top: 20px;
}

24
src/wwwroot/index.html Normal file
View File

@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<title>myPrayerJournal</title>
<base href="/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="/content/styles.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="/app.js"></script>
</head>
<body>
<div id="app"></div>
<script>
var app = Elm.App.embed(document.getElementById('app'))
app.ports.documentTitle.subscribe(function (title)
{
alert("Setting title to " + title)
document.title = title
})
</script>
</body>
</html>