commit 52bf643dea55e51cfccff24b0f4fcf20a18eda7a Author: Yehowshua Immanuel Date: Sat Dec 28 21:09:53 2024 -0500 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a22bdea --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +elm-stuff/ +elm.js +elm.min.js +node_modules/ +package-lock.json +package.json \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c6f0e2c --- /dev/null +++ b/Makefile @@ -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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..39b0496 --- /dev/null +++ b/README.md @@ -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` diff --git a/elm.json b/elm.json new file mode 100644 index 0000000..4217bec --- /dev/null +++ b/elm.json @@ -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": {} + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..f77df87 --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + + Elm UI Website + + +
+ + + + diff --git a/optimize.sh b/optimize.sh new file mode 100755 index 0000000..707dc0b --- /dev/null +++ b/optimize.sh @@ -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" \ No newline at end of file diff --git a/src/Header.elm b/src/Header.elm new file mode 100644 index 0000000..4cf08f8 --- /dev/null +++ b/src/Header.elm @@ -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 + ] diff --git a/src/Main.elm b/src/Main.elm new file mode 100644 index 0000000..89a95c0 --- /dev/null +++ b/src/Main.elm @@ -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 + } diff --git a/src/Page/Landing.elm b/src/Page/Landing.elm new file mode 100644 index 0000000..3767af0 --- /dev/null +++ b/src/Page/Landing.elm @@ -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"