first commit
This commit is contained in:
commit
52bf643dea
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
elm-stuff/
|
||||||
|
elm.js
|
||||||
|
elm.min.js
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
package.json
|
10
Makefile
Normal file
10
Makefile
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
SRC_FILES := $(shell find src -name "*.elm")
|
||||||
|
|
||||||
|
all: elm.min.js
|
||||||
|
|
||||||
|
serve: all
|
||||||
|
python3 -m http.server
|
||||||
|
|
||||||
|
elm.min.js: $(SRC_FILES)
|
||||||
|
rm -f elm.min.js elm.js
|
||||||
|
./optimize.sh src/Main.elm
|
27
README.md
Normal file
27
README.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# About
|
||||||
|
Example demonstrating how one might architect a single page application
|
||||||
|
Elm app.
|
||||||
|
|
||||||
|
# Dependencies MacOS
|
||||||
|
```bash
|
||||||
|
brew install node elm
|
||||||
|
npm install -g uglify-js@2.4.11
|
||||||
|
```
|
||||||
|
|
||||||
|
# Building
|
||||||
|
```
|
||||||
|
make serve
|
||||||
|
```
|
||||||
|
|
||||||
|
Now open `http://localhost:8000` in your browser.
|
||||||
|
|
||||||
|
# Viewing
|
||||||
|
|
||||||
|
Open index.html in your browser.
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
- [x] Add Makefile
|
||||||
|
- [ ] Refactor into router page
|
||||||
|
- [ ] Handle back-navigation
|
||||||
|
- [ ] Add `default.nix`
|
25
elm.json
Normal file
25
elm.json
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"type": "application",
|
||||||
|
"source-directories": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"elm-version": "0.19.1",
|
||||||
|
"dependencies": {
|
||||||
|
"direct": {
|
||||||
|
"elm/browser": "1.0.2",
|
||||||
|
"elm/core": "1.0.5",
|
||||||
|
"elm/html": "1.0.0",
|
||||||
|
"elm/url": "1.0.0",
|
||||||
|
"mdgriffith/elm-ui": "1.1.8"
|
||||||
|
},
|
||||||
|
"indirect": {
|
||||||
|
"elm/json": "1.1.3",
|
||||||
|
"elm/time": "1.0.0",
|
||||||
|
"elm/virtual-dom": "1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test-dependencies": {
|
||||||
|
"direct": {},
|
||||||
|
"indirect": {}
|
||||||
|
}
|
||||||
|
}
|
16
index.html
Normal file
16
index.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Elm UI Website</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="elm"></div>
|
||||||
|
<script src="elm.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var app = Elm.Main.init({
|
||||||
|
node: document.getElementById('elm')
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
14
optimize.sh
Executable file
14
optimize.sh
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
js="elm.js"
|
||||||
|
min="elm.min.js"
|
||||||
|
|
||||||
|
elm make --optimize --output=$js "$@"
|
||||||
|
|
||||||
|
uglifyjs $js --compress 'pure_funcs=[F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9],pure_getters,keep_fargs=false,unsafe_comps,unsafe' | uglifyjs --mangle --output $min
|
||||||
|
|
||||||
|
echo "Compiled size:$(wc $js -c) bytes ($js)"
|
||||||
|
echo "Minified size:$(wc $min -c) bytes ($min)"
|
||||||
|
echo "Gzipped size: $(gzip $min -c | wc -c) bytes"
|
44
src/Header.elm
Normal file
44
src/Header.elm
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
module Header exposing (Model, Msg(..), view, init)
|
||||||
|
import Element exposing (Element)
|
||||||
|
import Element.Events
|
||||||
|
import Element.Border
|
||||||
|
|
||||||
|
type alias Model = {}
|
||||||
|
type Msg
|
||||||
|
= ClickedProducts
|
||||||
|
| ClickedResources
|
||||||
|
| ClickedAbout
|
||||||
|
| ClickedContact
|
||||||
|
|
||||||
|
init : () -> Model
|
||||||
|
init flags = {}
|
||||||
|
|
||||||
|
view : Model -> Element Msg
|
||||||
|
view model =
|
||||||
|
let
|
||||||
|
dropShadow = Element.Border.shadow {
|
||||||
|
offset = ( 0, 2 ),
|
||||||
|
size = 1,
|
||||||
|
blur = 5,
|
||||||
|
color = Element.rgba 0 0 0 0.15
|
||||||
|
}
|
||||||
|
headerButton msg string =
|
||||||
|
Element.el
|
||||||
|
[Element.alignRight, Element.Events.onClick <| msg]
|
||||||
|
(Element.text string)
|
||||||
|
|
||||||
|
products = headerButton ClickedProducts "Products"
|
||||||
|
resources = headerButton ClickedResources "Resources"
|
||||||
|
about = headerButton ClickedAbout "About"
|
||||||
|
contact = headerButton ClickedContact "Contact"
|
||||||
|
in
|
||||||
|
Element.row [Element.width Element.fill,
|
||||||
|
Element.spacing 15,
|
||||||
|
Element.paddingXY 30 25,
|
||||||
|
dropShadow]
|
||||||
|
[ Element.el [Element.alignLeft] (Element.text "Elm Example App")
|
||||||
|
, products
|
||||||
|
, resources
|
||||||
|
, about
|
||||||
|
, contact
|
||||||
|
]
|
122
src/Main.elm
Normal file
122
src/Main.elm
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
module Main exposing (main)
|
||||||
|
|
||||||
|
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 Html exposing (header)
|
||||||
|
|
||||||
|
|
||||||
|
-- MODEL
|
||||||
|
type Page
|
||||||
|
= Landing Page.Landing.Model
|
||||||
|
| Products
|
||||||
|
| Resources
|
||||||
|
| About
|
||||||
|
| Contact
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ key : Browser.Navigation.Key
|
||||||
|
, url : Url.Url
|
||||||
|
, page : Page
|
||||||
|
, header : Header.Model}
|
||||||
|
|
||||||
|
init : () -> Url.Url -> Browser.Navigation.Key -> ( Model, Cmd Msg )
|
||||||
|
init flags url key =
|
||||||
|
let
|
||||||
|
page = Landing (Page.Landing.init flags)
|
||||||
|
header = Header.init flags
|
||||||
|
model =
|
||||||
|
{ key = key
|
||||||
|
, url = url
|
||||||
|
, page = page
|
||||||
|
, header = header
|
||||||
|
}
|
||||||
|
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
|
||||||
|
| LinkedClicked Browser.UrlRequest
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> (Model, Cmd Msg)
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
Header headerMsg ->
|
||||||
|
let
|
||||||
|
newUrl = toUrl model.url headerMsg
|
||||||
|
newModel = { model | page = toPage headerMsg }
|
||||||
|
in
|
||||||
|
(newModel, Browser.Navigation.pushUrl model.key (Url.toString newUrl))
|
||||||
|
_ -> (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
|
||||||
|
page =
|
||||||
|
Element.column
|
||||||
|
[ Element.width Element.fill
|
||||||
|
, Element.height Element.fill
|
||||||
|
, Element.centerX]
|
||||||
|
[ Header.view model.header |> Element.map Header
|
||||||
|
, viewBody model]
|
||||||
|
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 = LinkedClicked
|
||||||
|
}
|
13
src/Page/Landing.elm
Normal file
13
src/Page/Landing.elm
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
module Page.Landing exposing (Model, Msg, view, init)
|
||||||
|
import Element exposing (Element)
|
||||||
|
|
||||||
|
type alias Model = {}
|
||||||
|
type alias Msg = {}
|
||||||
|
|
||||||
|
init : () -> Model
|
||||||
|
init flags = {}
|
||||||
|
|
||||||
|
view : Model -> Element Msg
|
||||||
|
view model =
|
||||||
|
Element.el []
|
||||||
|
<| Element.text "Landing"
|
Loading…
Reference in a new issue