first commit

This commit is contained in:
Yehowshua Immanuel 2024-12-28 21:09:53 -05:00
commit 52bf643dea
9 changed files with 277 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
elm-stuff/
elm.js
elm.min.js
node_modules/
package-lock.json
package.json

10
Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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"