mirror of
https://gitlab.com/upRootNutrition/dotfiles.git
synced 2025-07-04 18:45:00 -05:00
feat: improved elm template
This commit is contained in:
parent
8545d7c1e8
commit
6b2a601776
22 changed files with 2139 additions and 0 deletions
7
templates/elm/frontend/.gitignore
vendored
Normal file
7
templates/elm/frontend/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/dist
|
||||
/.elm-land
|
||||
/.env
|
||||
/elm-stuff
|
||||
/node_modules
|
||||
.DS_Store
|
||||
*.pem
|
16
templates/elm/frontend/README.md
Normal file
16
templates/elm/frontend/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# frontend
|
||||
> Built with [Elm Land](https://elm.land) 🌈
|
||||
|
||||
## Local development
|
||||
|
||||
```bash
|
||||
# Requires Node.js v18+ (https://nodejs.org)
|
||||
npx elm-land server
|
||||
```
|
||||
|
||||
## Deploying to production
|
||||
|
||||
Elm Land projects are most commonly deployed as static websites.
|
||||
|
||||
Please visit [the "Deployment" guide](https://elm.land/guide/deploying) to learn more
|
||||
about deploying your app for free using Netlify or Vercel.
|
26
templates/elm/frontend/elm-land.json
Normal file
26
templates/elm/frontend/elm-land.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"app": {
|
||||
"elm": {
|
||||
"development": { "debugger": true },
|
||||
"production": { "debugger": false }
|
||||
},
|
||||
"env": [],
|
||||
"html": {
|
||||
"attributes": {
|
||||
"html": { "lang": "en" },
|
||||
"head": {}
|
||||
},
|
||||
"title": "Elm Land",
|
||||
"meta": [
|
||||
{ "charset": "UTF-8" },
|
||||
{ "http-equiv": "X-UA-Compatible", "content": "IE=edge" },
|
||||
{ "name": "viewport", "content": "width=device-width, initial-scale=1.0" }
|
||||
],
|
||||
"link": [],
|
||||
"script": []
|
||||
},
|
||||
"router": {
|
||||
"useHashRouting": false
|
||||
}
|
||||
}
|
||||
}
|
53
templates/elm/frontend/elm.json
Normal file
53
templates/elm/frontend/elm.json
Normal file
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"type": "application",
|
||||
"source-directories": [
|
||||
"src",
|
||||
".elm-land/src"
|
||||
],
|
||||
"elm-version": "0.19.1",
|
||||
"dependencies": {
|
||||
"direct": {
|
||||
"dillonkearns/elm-markdown": "7.0.1",
|
||||
"elm/browser": "1.0.2",
|
||||
"elm/core": "1.0.5",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/json": "1.1.3",
|
||||
"elm/svg": "1.0.1",
|
||||
"elm/url": "1.0.0",
|
||||
"elm-community/list-extra": "8.7.0",
|
||||
"elm-community/maybe-extra": "5.3.0",
|
||||
"gampleman/elm-visualization": "2.4.2",
|
||||
"hecrj/html-parser": "2.4.0",
|
||||
"mdgriffith/elm-ui": "1.1.8"
|
||||
},
|
||||
"indirect": {
|
||||
"avh4/elm-color": "1.0.0",
|
||||
"elm/parser": "1.1.0",
|
||||
"elm/random": "1.0.0",
|
||||
"elm/regex": "1.0.0",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.3",
|
||||
"elmcraft/core-extra": "2.2.0",
|
||||
"folkertdev/elm-deque": "3.0.1",
|
||||
"folkertdev/one-true-path-experiment": "6.0.1",
|
||||
"folkertdev/svg-path-lowlevel": "4.0.1",
|
||||
"gampleman/elm-rosetree": "1.1.0",
|
||||
"ianmackenzie/elm-1d-parameter": "1.0.1",
|
||||
"ianmackenzie/elm-float-extra": "1.1.0",
|
||||
"ianmackenzie/elm-geometry": "3.11.0",
|
||||
"ianmackenzie/elm-interval": "3.1.0",
|
||||
"ianmackenzie/elm-triangular-mesh": "1.1.0",
|
||||
"ianmackenzie/elm-units": "2.10.0",
|
||||
"ianmackenzie/elm-units-interval": "3.2.0",
|
||||
"ianmackenzie/elm-units-prefixed": "2.8.0",
|
||||
"justinmimbs/date": "4.1.0",
|
||||
"justinmimbs/time-extra": "1.2.0",
|
||||
"rtfeldman/elm-hex": "1.0.0",
|
||||
"ryan-haskell/date-format": "1.0.0"
|
||||
}
|
||||
},
|
||||
"test-dependencies": {
|
||||
"direct": {},
|
||||
"indirect": {}
|
||||
}
|
||||
}
|
94
templates/elm/frontend/src/Config/Helpers/Response.elm
Executable file
94
templates/elm/frontend/src/Config/Helpers/Response.elm
Executable file
|
@ -0,0 +1,94 @@
|
|||
module Config.Helpers.Response exposing
|
||||
( contentContainer
|
||||
, pageList
|
||||
, pageListCenter
|
||||
, pageListFormat
|
||||
, topLevelContainer
|
||||
)
|
||||
|
||||
import Config.Style.Colour.Helpers exposing (colourTheme)
|
||||
import Element as E
|
||||
exposing
|
||||
( Attribute
|
||||
, Device
|
||||
, DeviceClass(..)
|
||||
, Element
|
||||
, Orientation(..)
|
||||
, alignTop
|
||||
, centerX
|
||||
, centerY
|
||||
, el
|
||||
, fill
|
||||
, height
|
||||
, maximum
|
||||
, minimum
|
||||
, padding
|
||||
, paddingXY
|
||||
, scrollbarY
|
||||
, spacing
|
||||
, width
|
||||
)
|
||||
import Element.Background as B exposing (color)
|
||||
import Html.Attributes exposing (style)
|
||||
|
||||
|
||||
topLevelContainer : Element msg -> Element msg
|
||||
topLevelContainer =
|
||||
el
|
||||
[ width fill
|
||||
, height fill
|
||||
, B.color colourTheme.backgroundLightGrey
|
||||
]
|
||||
|
||||
|
||||
pageListCenter : Device -> List (Attribute msg)
|
||||
pageListCenter device =
|
||||
[ centerY
|
||||
]
|
||||
++ pageListFormat device
|
||||
|
||||
|
||||
pageList : Device -> List (Attribute msg)
|
||||
pageList device =
|
||||
[ alignTop
|
||||
]
|
||||
++ pageListFormat device
|
||||
|
||||
|
||||
pageListFormat : Device -> List (Attribute msg)
|
||||
pageListFormat device =
|
||||
let
|
||||
pageListAttr =
|
||||
[ centerX
|
||||
, width fill
|
||||
, height fill
|
||||
, scrollbarY
|
||||
]
|
||||
in
|
||||
pageListAttr
|
||||
++ (case ( device.class, device.orientation ) of
|
||||
( Phone, Portrait ) ->
|
||||
[ spacing 0
|
||||
, paddingXY 10 30
|
||||
]
|
||||
|
||||
( Tablet, Portrait ) ->
|
||||
[ spacing 0
|
||||
, paddingXY 10 30
|
||||
]
|
||||
|
||||
_ ->
|
||||
[ spacing 20
|
||||
, paddingXY 30 30
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
contentContainer : Element msg -> Element msg
|
||||
contentContainer =
|
||||
el
|
||||
[ width (fill |> minimum 100)
|
||||
, width (fill |> maximum 875)
|
||||
, padding 10
|
||||
, centerX
|
||||
]
|
16
templates/elm/frontend/src/Config/Helpers/Viewport.elm
Executable file
16
templates/elm/frontend/src/Config/Helpers/Viewport.elm
Executable file
|
@ -0,0 +1,16 @@
|
|||
module Config.Helpers.Viewport exposing
|
||||
( Msg
|
||||
, resetViewport
|
||||
)
|
||||
|
||||
import Browser.Dom as Dom exposing (setViewport)
|
||||
import Task exposing (attempt)
|
||||
|
||||
|
||||
type Msg
|
||||
= NoOp
|
||||
|
||||
|
||||
resetViewport : Cmd Msg
|
||||
resetViewport =
|
||||
Task.attempt (\_ -> NoOp) (Dom.setViewportOf "scroll-container" 0 0)
|
118
templates/elm/frontend/src/Config/Style/Colour/Helpers.elm
Executable file
118
templates/elm/frontend/src/Config/Style/Colour/Helpers.elm
Executable file
|
@ -0,0 +1,118 @@
|
|||
module Config.Style.Colour.Helpers exposing
|
||||
( ThemeColor(..)
|
||||
, colourTheme
|
||||
, getThemeColor
|
||||
, syntaxTheme
|
||||
)
|
||||
|
||||
import Config.Style.Colour.Types
|
||||
exposing
|
||||
( SyntaxColors
|
||||
, Theme
|
||||
)
|
||||
import Element as E
|
||||
exposing
|
||||
( Color
|
||||
, rgb255
|
||||
, rgba
|
||||
)
|
||||
import Element.Font as F exposing (color)
|
||||
|
||||
|
||||
colourTheme : Theme
|
||||
colourTheme =
|
||||
{ textLightGrey = rgb255 212 212 212
|
||||
, textDarkGrey = rgb255 126 126 126
|
||||
, textLightOrange = rgb255 204 102 0
|
||||
, textDarkOrange = rgb255 120 60 0
|
||||
, textDeepDarkOrange = rgb255 60 30 0
|
||||
, backgroundLightGrey = rgb255 40 40 40
|
||||
, backgroundDarkGrey = rgb255 30 30 30
|
||||
, backgroundDeepDarkGrey = rgb255 20 20 20
|
||||
, backgroundSpreadsheet = rgb255 36 36 36
|
||||
, backgroundSpreadsheetDark = rgb255 26 26 26
|
||||
, shadow = rgb255 10 10 10
|
||||
, barGreen = rgb255 0 102 0
|
||||
, barRed = rgb255 102 0 0
|
||||
, debugColour = rgb255 227 28 121
|
||||
, transparent = rgba 1 1 1 0
|
||||
}
|
||||
|
||||
|
||||
syntaxTheme : SyntaxColors
|
||||
syntaxTheme =
|
||||
{ punctuation = rgb255 202 158 230
|
||||
, key = rgb255 138 173 244
|
||||
, string = rgb255 166 218 149
|
||||
, keyword = rgb255 245 169 127
|
||||
, operator = rgb255 178 185 194
|
||||
, background = rgb255 36 39 58
|
||||
, text = rgb255 202 211 245
|
||||
}
|
||||
|
||||
|
||||
type ThemeColor
|
||||
= TextLightGrey
|
||||
| TextDarkGrey
|
||||
| TextLightOrange
|
||||
| TextDarkOrange
|
||||
| TextDeepDarkOrange
|
||||
| BackgroundLightGrey
|
||||
| BackgroundDarkGrey
|
||||
| BackgroundDeepDarkGrey
|
||||
| BackgroundSpreadsheet
|
||||
| BackgroundSpreadsheetDark
|
||||
| Shadow
|
||||
| BarGreen
|
||||
| BarRed
|
||||
| DebugColour
|
||||
| Transparent
|
||||
|
||||
|
||||
getThemeColor : ThemeColor -> Color
|
||||
getThemeColor color =
|
||||
case color of
|
||||
TextLightGrey ->
|
||||
colourTheme.textLightGrey
|
||||
|
||||
TextDarkGrey ->
|
||||
colourTheme.textDarkGrey
|
||||
|
||||
TextLightOrange ->
|
||||
colourTheme.textLightOrange
|
||||
|
||||
TextDarkOrange ->
|
||||
colourTheme.textDarkOrange
|
||||
|
||||
TextDeepDarkOrange ->
|
||||
colourTheme.textDeepDarkOrange
|
||||
|
||||
BackgroundLightGrey ->
|
||||
colourTheme.backgroundLightGrey
|
||||
|
||||
BackgroundDarkGrey ->
|
||||
colourTheme.backgroundDarkGrey
|
||||
|
||||
BackgroundDeepDarkGrey ->
|
||||
colourTheme.backgroundDeepDarkGrey
|
||||
|
||||
BackgroundSpreadsheet ->
|
||||
colourTheme.backgroundSpreadsheet
|
||||
|
||||
BackgroundSpreadsheetDark ->
|
||||
colourTheme.backgroundSpreadsheetDark
|
||||
|
||||
Shadow ->
|
||||
colourTheme.shadow
|
||||
|
||||
BarGreen ->
|
||||
colourTheme.barGreen
|
||||
|
||||
BarRed ->
|
||||
colourTheme.barRed
|
||||
|
||||
DebugColour ->
|
||||
colourTheme.debugColour
|
||||
|
||||
Transparent ->
|
||||
colourTheme.transparent
|
36
templates/elm/frontend/src/Config/Style/Colour/Types.elm
Executable file
36
templates/elm/frontend/src/Config/Style/Colour/Types.elm
Executable file
|
@ -0,0 +1,36 @@
|
|||
module Config.Style.Colour.Types exposing
|
||||
( SyntaxColors
|
||||
, Theme
|
||||
)
|
||||
|
||||
import Element exposing (Color)
|
||||
|
||||
|
||||
type alias Theme =
|
||||
{ textLightGrey : Color
|
||||
, textDarkGrey : Color
|
||||
, textLightOrange : Color
|
||||
, textDarkOrange : Color
|
||||
, textDeepDarkOrange : Color
|
||||
, backgroundLightGrey : Color
|
||||
, backgroundDarkGrey : Color
|
||||
, backgroundDeepDarkGrey : Color
|
||||
, backgroundSpreadsheet : Color
|
||||
, backgroundSpreadsheetDark : Color
|
||||
, shadow : Color
|
||||
, barGreen : Color
|
||||
, barRed : Color
|
||||
, debugColour : Color
|
||||
, transparent : Color
|
||||
}
|
||||
|
||||
|
||||
type alias SyntaxColors =
|
||||
{ punctuation : Color
|
||||
, key : Color
|
||||
, string : Color
|
||||
, keyword : Color
|
||||
, operator : Color
|
||||
, background : Color
|
||||
, text : Color
|
||||
}
|
50
templates/elm/frontend/src/Config/Style/Fonts.elm
Executable file
50
templates/elm/frontend/src/Config/Style/Fonts.elm
Executable file
|
@ -0,0 +1,50 @@
|
|||
module Config.Style.Fonts exposing
|
||||
( defaultFontSize
|
||||
, headerFontSizeBig
|
||||
, headerFontSizeMedium
|
||||
, paragraphSpacing
|
||||
, smallTextFontSize
|
||||
, spartanFont
|
||||
)
|
||||
|
||||
import Element
|
||||
exposing
|
||||
( Attr
|
||||
, Attribute
|
||||
, spacing
|
||||
)
|
||||
import Element.Font as F
|
||||
exposing
|
||||
( size
|
||||
, typeface
|
||||
)
|
||||
|
||||
|
||||
spartanFont : F.Font
|
||||
spartanFont =
|
||||
F.typeface "League Spartan"
|
||||
|
||||
|
||||
paragraphSpacing : Attribute msg
|
||||
paragraphSpacing =
|
||||
spacing 0
|
||||
|
||||
|
||||
headerFontSizeBig : Attr decorative msg
|
||||
headerFontSizeBig =
|
||||
F.size 23
|
||||
|
||||
|
||||
headerFontSizeMedium : Attr decorative msg
|
||||
headerFontSizeMedium =
|
||||
F.size 20
|
||||
|
||||
|
||||
defaultFontSize : Attr decorative msg
|
||||
defaultFontSize =
|
||||
F.size 18
|
||||
|
||||
|
||||
smallTextFontSize : Attr decorative msg
|
||||
smallTextFontSize =
|
||||
F.size 16
|
24
templates/elm/frontend/src/Config/Style/Glow.elm
Executable file
24
templates/elm/frontend/src/Config/Style/Glow.elm
Executable file
|
@ -0,0 +1,24 @@
|
|||
module Config.Style.Glow exposing
|
||||
( glowDeepDarkGrey
|
||||
, glowDeepDarkGreyNavbar
|
||||
, glowDeepDarkOrange
|
||||
)
|
||||
|
||||
import Config.Style.Colour.Helpers exposing (ThemeColor(..), colourTheme, getThemeColor)
|
||||
import Element exposing (Attr)
|
||||
import Element.Border as D exposing (glow)
|
||||
|
||||
|
||||
glowDeepDarkGrey : Attr decorative msg
|
||||
glowDeepDarkGrey =
|
||||
D.glow (getThemeColor Shadow) 4
|
||||
|
||||
|
||||
glowDeepDarkOrange : Attr decorative msg
|
||||
glowDeepDarkOrange =
|
||||
D.glow (getThemeColor TextDeepDarkOrange) 4
|
||||
|
||||
|
||||
glowDeepDarkGreyNavbar : Attr decorative msg
|
||||
glowDeepDarkGreyNavbar =
|
||||
D.glow (getThemeColor Shadow) 10
|
32
templates/elm/frontend/src/Config/Style/Icons/Helpers.elm
Executable file
32
templates/elm/frontend/src/Config/Style/Icons/Helpers.elm
Executable file
|
@ -0,0 +1,32 @@
|
|||
module Config.Style.Icons.Helpers exposing (buildSvg)
|
||||
|
||||
import Config.Style.Icons.Types as SvgTypes
|
||||
exposing
|
||||
( InnerPart
|
||||
, OuterPart
|
||||
)
|
||||
import Element as E
|
||||
exposing
|
||||
( Element
|
||||
, el
|
||||
, html
|
||||
)
|
||||
import Svg exposing (svg)
|
||||
|
||||
|
||||
|
||||
{- buildSvg consumes an inner record to construct most of an SVG, and an outer record to supply
|
||||
any potentially varying TypedSvg.Core.Attribute msgs and wrap it in an Element.el so it can be
|
||||
used by elm-ui. It provides a consistent interface for inserting SVGs into elm-ui code.
|
||||
-}
|
||||
|
||||
|
||||
buildSvg : SvgTypes.OuterPart msg -> SvgTypes.InnerPart msg -> Element msg
|
||||
buildSvg outer inner =
|
||||
el
|
||||
outer.elementAttributes
|
||||
<|
|
||||
html <|
|
||||
Svg.svg
|
||||
(outer.svgAttributes ++ inner.svgAttributes)
|
||||
inner.svg
|
1038
templates/elm/frontend/src/Config/Style/Icons/Icons.elm
Executable file
1038
templates/elm/frontend/src/Config/Style/Icons/Icons.elm
Executable file
File diff suppressed because it is too large
Load diff
28
templates/elm/frontend/src/Config/Style/Icons/Types.elm
Executable file
28
templates/elm/frontend/src/Config/Style/Icons/Types.elm
Executable file
|
@ -0,0 +1,28 @@
|
|||
module Config.Style.Icons.Types exposing
|
||||
( InnerPart
|
||||
, OuterPart
|
||||
)
|
||||
|
||||
{-| The types used for SVG management.
|
||||
-}
|
||||
|
||||
import Element exposing (Attribute)
|
||||
import Shared exposing (Model)
|
||||
import Svg exposing (svg)
|
||||
|
||||
|
||||
{-| The outer record for the SVG builder. This is explained in ../Helpers/Svg.elm.
|
||||
-}
|
||||
type alias OuterPart msg =
|
||||
{ elementAttributes : List (Element.Attribute msg)
|
||||
, sharedModel : Shared.Model
|
||||
, svgAttributes : List (Svg.Attribute msg)
|
||||
}
|
||||
|
||||
|
||||
{-| The inner record for the SVG builder. This is explained in ../Helpers/Svg.elm.
|
||||
-}
|
||||
type alias InnerPart msg =
|
||||
{ svgAttributes : List (Svg.Attribute msg)
|
||||
, svg : List (Svg.Svg msg)
|
||||
}
|
69
templates/elm/frontend/src/Config/Style/Transitions.elm
Executable file
69
templates/elm/frontend/src/Config/Style/Transitions.elm
Executable file
|
@ -0,0 +1,69 @@
|
|||
module Config.Style.Transitions exposing (..)
|
||||
|
||||
import Config.Style.Colour.Helpers exposing (colourTheme)
|
||||
import Config.Style.Glow
|
||||
exposing
|
||||
( glowDeepDarkGrey
|
||||
, glowDeepDarkOrange
|
||||
)
|
||||
import Element
|
||||
exposing
|
||||
( Attribute
|
||||
, htmlAttribute
|
||||
, mouseOver
|
||||
)
|
||||
import Element.Background as B exposing (color)
|
||||
import Element.Border as D exposing (color)
|
||||
import Element.Font as F exposing (color)
|
||||
import Html.Attributes as H exposing (style)
|
||||
|
||||
|
||||
transitionStyleSlow : Attribute msg
|
||||
transitionStyleSlow =
|
||||
htmlAttribute <| style "transition" "all 0.4s ease-in-out"
|
||||
|
||||
|
||||
transitionStyleMedium : Attribute msg
|
||||
transitionStyleMedium =
|
||||
htmlAttribute <| style "transition" "all 0.2s ease-in-out"
|
||||
|
||||
|
||||
transitionStyleFast : Attribute msg
|
||||
transitionStyleFast =
|
||||
htmlAttribute <| style "transition" "all 0.1s ease-in-out"
|
||||
|
||||
|
||||
specialNavbarTransition : Attribute msg
|
||||
specialNavbarTransition =
|
||||
htmlAttribute <| style "transition" "opacity .4s"
|
||||
|
||||
|
||||
|
||||
-- This special transition is needed to avoid weird animation sequencing rather in Chrome-based browsers.
|
||||
|
||||
|
||||
hoverFontLightOrange : Attribute msg
|
||||
hoverFontLightOrange =
|
||||
mouseOver [ F.color colourTheme.textLightOrange ]
|
||||
|
||||
|
||||
hoverFontDarkOrange : Attribute msg
|
||||
hoverFontDarkOrange =
|
||||
mouseOver [ F.color colourTheme.textDarkOrange ]
|
||||
|
||||
|
||||
hoverCircleButtonDarkOrange : Attribute msg
|
||||
hoverCircleButtonDarkOrange =
|
||||
mouseOver
|
||||
[ D.color colourTheme.textDarkOrange
|
||||
, B.color colourTheme.textDarkOrange
|
||||
, glowDeepDarkOrange
|
||||
]
|
||||
|
||||
|
||||
hoverPageButtonDeepDarkOrange : Attribute msg
|
||||
hoverPageButtonDeepDarkOrange =
|
||||
mouseOver
|
||||
[ B.color colourTheme.textDeepDarkOrange
|
||||
, F.color colourTheme.textLightOrange
|
||||
]
|
194
templates/elm/frontend/src/Effect.elm
Normal file
194
templates/elm/frontend/src/Effect.elm
Normal file
|
@ -0,0 +1,194 @@
|
|||
module Effect exposing
|
||||
( Effect
|
||||
, none, batch
|
||||
, sendCmd, sendMsg
|
||||
, pushRoute, replaceRoute, loadExternalUrl
|
||||
, map, toCmd
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs Effect
|
||||
@docs none, batch
|
||||
@docs sendCmd, sendMsg
|
||||
@docs pushRoute, replaceRoute, loadExternalUrl
|
||||
|
||||
@docs map, toCmd
|
||||
|
||||
-}
|
||||
|
||||
import Browser.Navigation
|
||||
import Dict exposing (Dict)
|
||||
import Route exposing (Route)
|
||||
import Route.Path
|
||||
import Shared.Model
|
||||
import Shared.Msg
|
||||
import Task
|
||||
import Url exposing (Url)
|
||||
|
||||
|
||||
type Effect msg
|
||||
= -- BASICS
|
||||
None
|
||||
| Batch (List (Effect msg))
|
||||
| SendCmd (Cmd msg)
|
||||
-- ROUTING
|
||||
| PushUrl String
|
||||
| ReplaceUrl String
|
||||
| LoadExternalUrl String
|
||||
-- SHARED
|
||||
| SendSharedMsg Shared.Msg.Msg
|
||||
|
||||
|
||||
|
||||
-- BASICS
|
||||
|
||||
|
||||
{-| Don't send any effect.
|
||||
-}
|
||||
none : Effect msg
|
||||
none =
|
||||
None
|
||||
|
||||
|
||||
{-| Send multiple effects at once.
|
||||
-}
|
||||
batch : List (Effect msg) -> Effect msg
|
||||
batch =
|
||||
Batch
|
||||
|
||||
|
||||
{-| Send a normal `Cmd msg` as an effect, something like `Http.get` or `Random.generate`.
|
||||
-}
|
||||
sendCmd : Cmd msg -> Effect msg
|
||||
sendCmd =
|
||||
SendCmd
|
||||
|
||||
|
||||
{-| Send a message as an effect. Useful when emitting events from UI components.
|
||||
-}
|
||||
sendMsg : msg -> Effect msg
|
||||
sendMsg msg =
|
||||
Task.succeed msg
|
||||
|> Task.perform identity
|
||||
|> SendCmd
|
||||
|
||||
|
||||
|
||||
-- ROUTING
|
||||
|
||||
|
||||
{-| Set the new route, and make the back button go back to the current route.
|
||||
-}
|
||||
pushRoute :
|
||||
{ path : Route.Path.Path
|
||||
, query : Dict String String
|
||||
, hash : Maybe String
|
||||
}
|
||||
-> Effect msg
|
||||
pushRoute route =
|
||||
PushUrl (Route.toString route)
|
||||
|
||||
{-| Set given path as route (without any query params or hash), and make the back button go back to the current route.
|
||||
-}
|
||||
pushPath :
|
||||
Route.Path.Path
|
||||
-> Effect msg
|
||||
pushPath path =
|
||||
PushUrl (Route.toString { path = path, query = Dict.empty, hash = Nothing })
|
||||
|
||||
{-| Set the new route, but replace the previous one, so clicking the back
|
||||
button **won't** go back to the previous route.
|
||||
-}
|
||||
replaceRoute :
|
||||
{ path : Route.Path.Path
|
||||
, query : Dict String String
|
||||
, hash : Maybe String
|
||||
}
|
||||
-> Effect msg
|
||||
replaceRoute route =
|
||||
ReplaceUrl (Route.toString route)
|
||||
|
||||
{-| Set given path as route (without any query params or hash), but replace the previous route,
|
||||
so clicking the back button **won't** go back to the previous route
|
||||
-}
|
||||
replacePath :
|
||||
Route.Path.Path
|
||||
-> Effect msg
|
||||
replacePath path =
|
||||
ReplaceUrl (Route.toString { path = path, query = Dict.empty, hash = Nothing })
|
||||
|
||||
{-| Redirect users to a new URL, somewhere external your web application.
|
||||
-}
|
||||
loadExternalUrl : String -> Effect msg
|
||||
loadExternalUrl =
|
||||
LoadExternalUrl
|
||||
|
||||
|
||||
|
||||
-- INTERNALS
|
||||
|
||||
|
||||
{-| Elm Land depends on this function to connect pages and layouts
|
||||
together into the overall app.
|
||||
-}
|
||||
map : (msg1 -> msg2) -> Effect msg1 -> Effect msg2
|
||||
map fn effect =
|
||||
case effect of
|
||||
None ->
|
||||
None
|
||||
|
||||
Batch list ->
|
||||
Batch (List.map (map fn) list)
|
||||
|
||||
SendCmd cmd ->
|
||||
SendCmd (Cmd.map fn cmd)
|
||||
|
||||
PushUrl url ->
|
||||
PushUrl url
|
||||
|
||||
ReplaceUrl url ->
|
||||
ReplaceUrl url
|
||||
|
||||
LoadExternalUrl url ->
|
||||
LoadExternalUrl url
|
||||
|
||||
SendSharedMsg sharedMsg ->
|
||||
SendSharedMsg sharedMsg
|
||||
|
||||
|
||||
{-| Elm Land depends on this function to perform your effects.
|
||||
-}
|
||||
toCmd :
|
||||
{ key : Browser.Navigation.Key
|
||||
, url : Url
|
||||
, shared : Shared.Model.Model
|
||||
, fromSharedMsg : Shared.Msg.Msg -> msg
|
||||
, batch : List msg -> msg
|
||||
, toCmd : msg -> Cmd msg
|
||||
}
|
||||
-> Effect msg
|
||||
-> Cmd msg
|
||||
toCmd options effect =
|
||||
case effect of
|
||||
None ->
|
||||
Cmd.none
|
||||
|
||||
Batch list ->
|
||||
Cmd.batch (List.map (toCmd options) list)
|
||||
|
||||
SendCmd cmd ->
|
||||
cmd
|
||||
|
||||
PushUrl url ->
|
||||
Browser.Navigation.pushUrl options.key url
|
||||
|
||||
ReplaceUrl url ->
|
||||
Browser.Navigation.replaceUrl options.key url
|
||||
|
||||
LoadExternalUrl url ->
|
||||
Browser.Navigation.load url
|
||||
|
||||
SendSharedMsg sharedMsg ->
|
||||
Task.succeed sharedMsg
|
||||
|> Task.perform options.fromSharedMsg
|
70
templates/elm/frontend/src/Pages/Home_.elm
Normal file
70
templates/elm/frontend/src/Pages/Home_.elm
Normal file
|
@ -0,0 +1,70 @@
|
|||
module Pages.Home_ exposing (Model, Msg, page)
|
||||
|
||||
import Effect exposing (Effect)
|
||||
import Route exposing (Route)
|
||||
import Html
|
||||
import Page exposing (Page)
|
||||
import Shared
|
||||
import View exposing (View)
|
||||
|
||||
|
||||
page : Shared.Model -> Route () -> Page Model Msg
|
||||
page shared route =
|
||||
Page.new
|
||||
{ init = init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, view = view
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- INIT
|
||||
|
||||
|
||||
type alias Model =
|
||||
{}
|
||||
|
||||
|
||||
init : () -> ( Model, Effect Msg )
|
||||
init () =
|
||||
( {}
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
type Msg
|
||||
= NoOp
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Effect Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
NoOp ->
|
||||
( model
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
Sub.none
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
|
||||
view : Model -> View Msg
|
||||
view model =
|
||||
{ title = "Pages.Home_"
|
||||
, body = [ Html.text "/" ]
|
||||
}
|
69
templates/elm/frontend/src/Pages/NotFound_.elm
Normal file
69
templates/elm/frontend/src/Pages/NotFound_.elm
Normal file
|
@ -0,0 +1,69 @@
|
|||
module Pages.NotFound_ exposing (Model, Msg, page)
|
||||
|
||||
import Effect exposing (Effect)
|
||||
import Html exposing (..)
|
||||
import Page exposing (Page)
|
||||
import Route exposing (Route)
|
||||
import Route.Path
|
||||
import Shared
|
||||
import View exposing (View)
|
||||
|
||||
|
||||
page : Shared.Model -> Route () -> Page Model Msg
|
||||
page shared route =
|
||||
Page.new
|
||||
{ init = init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, view = view
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- INIT
|
||||
|
||||
|
||||
type alias Model =
|
||||
{}
|
||||
|
||||
|
||||
init : () -> ( Model, Effect Msg )
|
||||
init () =
|
||||
( {}
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
type Msg
|
||||
= NoOp
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Effect Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
NoOp ->
|
||||
( model
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
Sub.none
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
|
||||
view : Model -> View Msg
|
||||
view model =
|
||||
View.fromString "Page not found"
|
74
templates/elm/frontend/src/Shared.elm
Normal file
74
templates/elm/frontend/src/Shared.elm
Normal file
|
@ -0,0 +1,74 @@
|
|||
module Shared exposing
|
||||
( Flags, decoder
|
||||
, Model, Msg
|
||||
, init, update, subscriptions
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs Flags, decoder
|
||||
@docs Model, Msg
|
||||
@docs init, update, subscriptions
|
||||
|
||||
-}
|
||||
|
||||
import Effect exposing (Effect)
|
||||
import Json.Decode
|
||||
import Route exposing (Route)
|
||||
import Route.Path
|
||||
import Shared.Model
|
||||
import Shared.Msg
|
||||
|
||||
|
||||
|
||||
-- FLAGS
|
||||
|
||||
|
||||
type alias Flags =
|
||||
{}
|
||||
|
||||
|
||||
decoder : Json.Decode.Decoder Flags
|
||||
decoder =
|
||||
Json.Decode.succeed {}
|
||||
|
||||
|
||||
|
||||
-- INIT
|
||||
|
||||
|
||||
type alias Model =
|
||||
Shared.Model.Model
|
||||
|
||||
|
||||
init : Result Json.Decode.Error Flags -> Route () -> ( Model, Effect Msg )
|
||||
init flagsResult route =
|
||||
( {}
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
type alias Msg =
|
||||
Shared.Msg.Msg
|
||||
|
||||
|
||||
update : Route () -> Msg -> Model -> ( Model, Effect Msg )
|
||||
update route msg model =
|
||||
case msg of
|
||||
Shared.Msg.NoOp ->
|
||||
( model
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Route () -> Model -> Sub Msg
|
||||
subscriptions route model =
|
||||
Sub.none
|
14
templates/elm/frontend/src/Shared/Model.elm
Normal file
14
templates/elm/frontend/src/Shared/Model.elm
Normal file
|
@ -0,0 +1,14 @@
|
|||
module Shared.Model exposing (Model)
|
||||
|
||||
{-| -}
|
||||
|
||||
|
||||
{-| Normally, this value would live in "Shared.elm"
|
||||
but that would lead to a circular dependency import cycle.
|
||||
|
||||
For that reason, both `Shared.Model` and `Shared.Msg` are in their
|
||||
own file, so they can be imported by `Effect.elm`
|
||||
|
||||
-}
|
||||
type alias Model =
|
||||
{}
|
14
templates/elm/frontend/src/Shared/Msg.elm
Normal file
14
templates/elm/frontend/src/Shared/Msg.elm
Normal file
|
@ -0,0 +1,14 @@
|
|||
module Shared.Msg exposing (Msg(..))
|
||||
|
||||
{-| -}
|
||||
|
||||
|
||||
{-| Normally, this value would live in "Shared.elm"
|
||||
but that would lead to a circular dependency import cycle.
|
||||
|
||||
For that reason, both `Shared.Model` and `Shared.Msg` are in their
|
||||
own file, so they can be imported by `Effect.elm`
|
||||
|
||||
-}
|
||||
type Msg
|
||||
= NoOp
|
72
templates/elm/frontend/src/View.elm
Normal file
72
templates/elm/frontend/src/View.elm
Normal file
|
@ -0,0 +1,72 @@
|
|||
module View exposing
|
||||
( View, map
|
||||
, none, fromString
|
||||
, toBrowserDocument
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs View, map
|
||||
@docs none, fromString
|
||||
@docs toBrowserDocument
|
||||
|
||||
-}
|
||||
|
||||
import Browser
|
||||
import Html exposing (Html)
|
||||
import Route exposing (Route)
|
||||
import Shared.Model
|
||||
|
||||
|
||||
type alias View msg =
|
||||
{ title : String
|
||||
, body : List (Html msg)
|
||||
}
|
||||
|
||||
|
||||
{-| Used internally by Elm Land to create your application
|
||||
so it works with Elm's expected `Browser.Document msg` type.
|
||||
-}
|
||||
toBrowserDocument :
|
||||
{ shared : Shared.Model.Model
|
||||
, route : Route ()
|
||||
, view : View msg
|
||||
}
|
||||
-> Browser.Document msg
|
||||
toBrowserDocument { view } =
|
||||
{ title = view.title
|
||||
, body = view.body
|
||||
}
|
||||
|
||||
|
||||
{-| Used internally by Elm Land to connect your pages together.
|
||||
-}
|
||||
map : (msg1 -> msg2) -> View msg1 -> View msg2
|
||||
map fn view =
|
||||
{ title = view.title
|
||||
, body = List.map (Html.map fn) view.body
|
||||
}
|
||||
|
||||
|
||||
{-| Used internally by Elm Land whenever transitioning between
|
||||
authenticated pages.
|
||||
-}
|
||||
none : View msg
|
||||
none =
|
||||
{ title = ""
|
||||
, body = []
|
||||
}
|
||||
|
||||
|
||||
{-| If you customize the `View` module, anytime you run `elm-land add page`,
|
||||
the generated page will use this when adding your `view` function.
|
||||
|
||||
That way your app will compile after adding new pages, and you can see
|
||||
the new page working in the web browser!
|
||||
|
||||
-}
|
||||
fromString : String -> View msg
|
||||
fromString moduleName =
|
||||
{ title = moduleName
|
||||
, body = [ Html.text moduleName ]
|
||||
}
|
25
templates/elm/frontend/src/interop.ts
Normal file
25
templates/elm/frontend/src/interop.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
// This returns the flags passed into your Elm application
|
||||
export const flags = async ({ env } : ElmLand.FlagsArgs) => {
|
||||
return {}
|
||||
}
|
||||
|
||||
// This function is called after your Elm app starts
|
||||
export const onReady = ({ app, env } : ElmLand.OnReadyArgs) => {
|
||||
console.log('Elm is ready', app)
|
||||
}
|
||||
|
||||
|
||||
// Type definitions for Elm Land
|
||||
namespace ElmLand {
|
||||
export type FlagsArgs = {
|
||||
env: Record<string, string>
|
||||
}
|
||||
export type OnReadyArgs = {
|
||||
env: Record<string, string>
|
||||
app: { ports?: Record<string, Port> }
|
||||
}
|
||||
export type Port = {
|
||||
send?: (data: unknown) => void
|
||||
subscribe?: (callback: (data: unknown) => unknown) => void
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue