Update init command.

This commit is contained in:
Dillon Kearns 2023-05-30 16:22:28 -07:00
parent 79fe88b2bc
commit f065f7a6cb
23 changed files with 929 additions and 99 deletions

View File

@ -1,6 +1,6 @@
module Api exposing (routes)
import ApiRoute
import ApiRoute exposing (ApiRoute)
import BackendTask exposing (BackendTask)
import FatalError exposing (FatalError)
import Html exposing (Html)
@ -11,7 +11,7 @@ import Route exposing (Route)
routes :
BackendTask FatalError (List Route)
-> (Maybe { indent : Int, newLines : Bool } -> Html Never -> String)
-> List (ApiRoute.ApiRoute ApiRoute.Response)
-> List (ApiRoute ApiRoute.Response)
routes getStaticRoutes htmlToString =
[]

View File

@ -1,17 +1,25 @@
module Effect exposing (Effect(..), batch, fromCmd, map, none, perform)
{-|
@docs Effect, batch, fromCmd, map, none, perform
-}
import Browser.Navigation
import Form.FormData exposing (FormData)
import Form
import Http
import Json.Decode as Decode
import Pages.Fetcher
import Url exposing (Url)
{-| -}
type Effect msg
= None
| Cmd (Cmd msg)
| Batch (List (Effect msg))
| GetStargazers (Result Http.Error Int -> msg)
| SetField { formId : String, name : String, value : String }
| FetchRouteData
{ data : Maybe FormData
@ -24,27 +32,32 @@ type Effect msg
| SubmitFetcher (Pages.Fetcher.Fetcher msg)
{-| -}
type alias RequestInfo =
{ contentType : String
, body : String
}
{-| -}
none : Effect msg
none =
None
{-| -}
batch : List (Effect msg) -> Effect msg
batch =
Batch
{-| -}
fromCmd : Cmd msg -> Effect msg
fromCmd =
Cmd
{-| -}
map : (a -> b) -> Effect a -> Effect b
map fn effect =
case effect of
@ -57,6 +70,9 @@ map fn effect =
Batch list ->
Batch (List.map (map fn) list)
GetStargazers toMsg ->
GetStargazers (toMsg >> fn)
FetchRouteData fetchInfo ->
FetchRouteData
{ data = fetchInfo.data
@ -78,6 +94,7 @@ map fn effect =
|> SubmitFetcher
{-| -}
perform :
{ fetchRouteData :
{ data : Maybe FormData
@ -112,6 +129,13 @@ perform ({ fromPageMsg, key } as helpers) effect =
Batch list ->
Cmd.batch (List.map (perform helpers) list)
GetStargazers toMsg ->
Http.get
{ url =
"https://api.github.com/repos/dillonkearns/elm-pages"
, expect = Http.expectJson (toMsg >> fromPageMsg) (Decode.field "stargazers_count" Decode.int)
}
FetchRouteData fetchInfo ->
helpers.fetchRouteData
fetchInfo
@ -121,3 +145,11 @@ perform ({ fromPageMsg, key } as helpers) effect =
SubmitFetcher record ->
helpers.runFetcher record
type alias FormData =
{ fields : List ( String, String )
, method : Form.Method
, action : String
, id : Maybe String
}

View File

@ -3,20 +3,22 @@ module ErrorPage exposing (ErrorPage(..), Model, Msg, head, init, internalError,
import Effect exposing (Effect)
import Head
import Html exposing (Html)
import Html.Events exposing (onClick)
import View exposing (View)
type Msg
= NoOp
= Increment
type alias Model =
{}
{ count : Int
}
init : ErrorPage -> ( Model, Effect Msg )
init errorPage =
( {}
( { count = 0 }
, Effect.none
)
@ -24,8 +26,8 @@ init errorPage =
update : ErrorPage -> Msg -> Model -> ( Model, Effect Msg )
update errorPage msg model =
case msg of
NoOp ->
( {}, Effect.none )
Increment ->
( { model | count = model.count + 1 }, Effect.none )
head : ErrorPage -> List Head.Tag
@ -53,9 +55,19 @@ view error model =
{ body =
[ Html.div []
[ Html.p [] [ Html.text "Page not found. Maybe try another URL?" ]
, Html.div []
[ Html.button
[ onClick Increment
]
[ Html.text
(model.count
|> String.fromInt
)
]
]
, title = "Page Not Found"
]
]
, title = "This is a NotFound Error"
}

View File

@ -0,0 +1,86 @@
module Route.Blog.Slug_ exposing (ActionData, Data, Model, Msg, route)
import BackendTask exposing (BackendTask)
import FatalError exposing (FatalError)
import Head
import Head.Seo as Seo
import Html
import Pages.Url
import PagesMsg exposing (PagesMsg)
import RouteBuilder exposing (App, StatelessRoute)
import Shared
import View exposing (View)
type alias Model =
{}
type alias Msg =
()
type alias RouteParams =
{ slug : String }
route : StatelessRoute RouteParams Data ActionData
route =
RouteBuilder.preRender
{ head = head
, pages = pages
, data = data
}
|> RouteBuilder.buildNoState { view = view }
pages : BackendTask FatalError (List RouteParams)
pages =
BackendTask.succeed
[ { slug = "hello" }
]
type alias Data =
{ something : String
}
type alias ActionData =
{}
data : RouteParams -> BackendTask FatalError Data
data routeParams =
BackendTask.map Data
(BackendTask.succeed "Hi")
head :
App Data ActionData RouteParams
-> List Head.Tag
head app =
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = Pages.Url.external "TODO"
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
}
, description = "TODO"
, locale = Nothing
, title = "TODO title" -- metadata.title -- TODO
}
|> Seo.website
view :
App Data ActionData RouteParams
-> Shared.Model
-> View (PagesMsg Msg)
view app sharedModel =
{ title = "Placeholder - Blog.Slug_"
, body = [ Html.text "You're on the page Blog.Slug_" ]
}

View File

@ -0,0 +1,107 @@
module Route.Greet exposing (ActionData, Data, Model, Msg, route)
import BackendTask exposing (BackendTask)
import BackendTask.Http
import ErrorPage exposing (ErrorPage)
import FatalError exposing (FatalError)
import Head
import Head.Seo as Seo
import Html
import Json.Decode as Decode
import Pages.Url
import PagesMsg exposing (PagesMsg)
import RouteBuilder exposing (App, StatefulRoute, StatelessRoute)
import Server.Request as Request exposing (Request)
import Server.Response as Response exposing (Response)
import Shared
import View exposing (View)
type alias Model =
{}
type alias Msg =
()
type alias RouteParams =
{}
route : StatelessRoute RouteParams Data ActionData
route =
RouteBuilder.serverRender
{ head = head
, data = data
, action = \_ _ -> BackendTask.fail (FatalError.fromString "No action.")
}
|> RouteBuilder.buildNoState { view = view }
type alias Data =
{ name : Maybe String
}
type alias ActionData =
{}
data : RouteParams -> Request -> BackendTask FatalError (Response Data ErrorPage)
data routeParams request =
case request |> Request.queryParam "name" of
Just name ->
BackendTask.Http.getJson "http://worldtimeapi.org/api/timezone/America/Los_Angeles"
(Decode.field "utc_datetime" Decode.string)
|> BackendTask.allowFatal
|> BackendTask.map
(\dateTimeString ->
Response.render
{ name = Just dateTimeString }
)
Nothing ->
BackendTask.succeed
(Response.render
{ name = Nothing }
)
head :
App Data ActionData RouteParams
-> List Head.Tag
head app =
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = Pages.Url.external "TODO"
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
}
, description = "TODO"
, locale = Nothing
, title = "TODO title" -- metadata.title -- TODO
}
|> Seo.website
view :
App Data ActionData RouteParams
-> Shared.Model
-> View (PagesMsg Msg)
view app shared =
{ title = "Greetings"
, body =
[ Html.div []
[ case app.data.name of
Just name ->
Html.text ("Hello " ++ name)
Nothing ->
Html.text "Hello, I didn't find your name"
]
]
}

View File

@ -0,0 +1,119 @@
module Route.Hello exposing (ActionData, Data, Model, Msg(..), RouteParams, action, data, route)
import BackendTask exposing (BackendTask)
import BackendTask.Http
import Effect exposing (Effect)
import ErrorPage exposing (ErrorPage)
import FatalError exposing (FatalError)
import Head
import Html
import Json.Decode as Decode
import PagesMsg exposing (PagesMsg)
import RouteBuilder exposing (App)
import Server.Request exposing (Request)
import Server.Response
import Shared
import UrlPath exposing (UrlPath)
import View exposing (View)
type alias Model =
{}
type Msg
= NoOp
type alias RouteParams =
{}
route =
RouteBuilder.serverRender { data = data, action = action, head = head }
|> RouteBuilder.buildWithLocalState
{ view = view
, subscriptions = subscriptions
, update = update
, init = init
}
init :
App Data ActionData RouteParams
-> Shared.Model
-> ( Model, Effect Msg )
init app shared =
( {}, Effect.none )
update :
App Data ActionData RouteParams
-> Shared.Model
-> Msg
-> Model
-> ( Model, Effect Msg )
update app shared msg model =
case msg of
NoOp ->
( model, Effect.none )
subscriptions :
RouteParams
-> UrlPath
-> Shared.Model
-> Model
-> Sub Msg
subscriptions routeParams path shared model =
Sub.none
type alias Data =
{ stars : Int
}
type alias ActionData =
{}
data :
RouteParams
-> Request
-> BackendTask FatalError (Server.Response.Response Data ErrorPage)
data routeParams request =
BackendTask.Http.getWithOptions
{ url = "https://api.github.com/repos/dillonkearns/elm-pages"
, expect = BackendTask.Http.expectJson (Decode.field "stargazers_count" Decode.int)
, headers = []
, cacheStrategy = Just BackendTask.Http.IgnoreCache
, retries = Nothing
, timeoutInMs = Nothing
, cachePath = Nothing
}
|> BackendTask.allowFatal
|> BackendTask.map
(\stars -> Server.Response.render { stars = stars })
head : App Data ActionData RouteParams -> List Head.Tag
head app =
[]
view :
App Data ActionData RouteParams
-> Shared.Model
-> Model
-> View (PagesMsg Msg)
view app shared model =
{ title = "Hello", body = [ Html.text (String.fromInt app.data.stars) ] }
action :
RouteParams
-> Request
-> BackendTask.BackendTask FatalError.FatalError (Server.Response.Response ActionData ErrorPage.ErrorPage)
action routeParams request =
BackendTask.succeed (Server.Response.render {})

View File

@ -5,13 +5,11 @@ import FatalError exposing (FatalError)
import Head
import Head.Seo as Seo
import Html
import Html.Styled.Attributes as Attr
import PagesMsg exposing (PagesMsg)
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
import Path
import PagesMsg exposing (PagesMsg)
import UrlPath
import Route
import RouteBuilder exposing (StatefulRoute, StatelessRoute, App)
import RouteBuilder exposing (App, StatelessRoute)
import Shared
import View exposing (View)
@ -28,6 +26,11 @@ type alias RouteParams =
{}
type alias Data =
{ message : String
}
type alias ActionData =
{}
@ -41,24 +44,22 @@ route =
|> RouteBuilder.buildNoState { view = view }
type alias Data =
()
data : BackendTask FatalError Data
data =
BackendTask.succeed ()
BackendTask.succeed Data
|> BackendTask.andMap
(BackendTask.succeed "Hello!")
head :
App Data ActionData RouteParams
-> List Head.Tag
head static =
head app =
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = [ "images", "icon-png.png" ] |> Path.join |> Pages.Url.fromPath
{ url = [ "images", "icon-png.png" ] |> UrlPath.join |> Pages.Url.fromPath
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
@ -71,24 +72,17 @@ head static =
view :
Maybe PageUrl
App Data ActionData RouteParams
-> Shared.Model
-> App Data ActionData RouteParams
-> View (PagesMsg Msg)
view maybeUrl sharedModel static =
view app shared =
{ title = "elm-pages is running"
, body =
[ Html.h1 [] [ Html.text "elm-pages is up and running!" ]
, Html.h2 [] [ Html.text "Learn more" ]
, Html.ul
[]
[ Html.li []
[ Html.a [ Attr.href "https://elm-pages.com/docs/" ] [ Html.text "Framework documentation" ]
]
, Html.li
[]
[ Html.a [ Attr.href "https://package.elm-lang.org/packages/dillonkearns/elm-pages/latest/" ] [ Html.text "Elm package documentation" ]
]
, Html.p []
[ Html.text <| "The message is: " ++ app.data.message
]
, Route.Blog__Slug_ { slug = "hello" }
|> Route.link [] [ Html.text "My blog post" ]
]
}

View File

@ -4,9 +4,10 @@ import BackendTask exposing (BackendTask)
import Effect exposing (Effect)
import FatalError exposing (FatalError)
import Html exposing (Html)
import Html.Events
import Pages.Flags
import Pages.PageUrl exposing (PageUrl)
import Path exposing (Path)
import UrlPath exposing (UrlPath)
import Route exposing (Route)
import SharedTemplate exposing (SharedTemplate)
import View exposing (View)
@ -19,16 +20,13 @@ template =
, view = view
, data = data
, subscriptions = subscriptions
, onPageChange = Just OnPageChange
, onPageChange = Nothing
}
type Msg
= OnPageChange
{ path : Path
, query : Maybe String
, fragment : Maybe String
}
= SharedMsg SharedMsg
| MenuClicked
type alias Data =
@ -40,7 +38,7 @@ type SharedMsg
type alias Model =
{ showMobileMenu : Bool
{ showMenu : Bool
}
@ -49,7 +47,7 @@ init :
->
Maybe
{ path :
{ path : Path
{ path : UrlPath
, query : Maybe String
, fragment : Maybe String
}
@ -58,7 +56,7 @@ init :
}
-> ( Model, Effect Msg )
init flags maybePagePath =
( { showMobileMenu = False }
( { showMenu = False }
, Effect.none
)
@ -66,11 +64,14 @@ init flags maybePagePath =
update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
case msg of
OnPageChange _ ->
( { model | showMobileMenu = False }, Effect.none )
SharedMsg globalMsg ->
( model, Effect.none )
MenuClicked ->
( { model | showMenu = not model.showMenu }, Effect.none )
subscriptions : Path -> Model -> Sub Msg
subscriptions : UrlPath -> Model -> Sub Msg
subscriptions _ _ =
Sub.none
@ -83,16 +84,37 @@ data =
view :
Data
->
{ path : Path
{ path : UrlPath
, route : Maybe Route
}
-> Model
-> (Msg -> msg)
-> View msg
-> { body : List (Html msg), title : String }
view stars page model toMsg pageView =
view sharedData page model toMsg pageView =
{ body =
[ Html.div [] pageView.body
[ Html.nav []
[ Html.button
[ Html.Events.onClick MenuClicked ]
[ Html.text
(if model.showMenu then
"Close Menu"
else
"Open Menu"
)
]
, if model.showMenu then
Html.ul []
[ Html.li [] [ Html.text "Menu item 1" ]
, Html.li [] [ Html.text "Menu item 2" ]
]
else
Html.text ""
]
|> Html.map toMsg
, Html.main_ [] pageView.body
]
, title = pageView.title
}

View File

@ -1,16 +1,14 @@
module Site exposing (canonicalUrl, config)
module Site exposing (config)
import BackendTask exposing (BackendTask)
import FatalError exposing (FatalError)
import Head
import MimeType
import Pages.Url
import SiteConfig exposing (SiteConfig)
config : SiteConfig
config =
{ canonicalUrl = canonicalUrl
{ canonicalUrl = "https://elm-pages.com"
, head = head
}
@ -18,15 +16,6 @@ config =
head : BackendTask FatalError (List Head.Tag)
head =
[ Head.metaName "viewport" (Head.raw "width=device-width,initial-scale=1")
, Head.metaName "mobile-web-app-capable" (Head.raw "yes")
, Head.metaName "theme-color" (Head.raw "#ffffff")
, Head.metaName "apple-mobile-web-app-capable" (Head.raw "yes")
, Head.metaName "apple-mobile-web-app-status-bar-style" (Head.raw "black-translucent")
, Head.sitemapLink "/sitemap.xml"
]
|> BackendTask.succeed
canonicalUrl : String
canonicalUrl =
"https://elm-pages.com"

View File

@ -1,14 +1,22 @@
module View exposing (View, map)
{-|
@docs View, map
-}
import Html exposing (Html)
{-| -}
type alias View msg =
{ title : String
, body : List (Html msg)
}
{-| -}
map : (msg1 -> msg2) -> View msg1 -> View msg2
map fn doc =
{ title = doc.title

2
generator/template/codegen/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
Gen/

View File

@ -0,0 +1,18 @@
{
"elm-codegen-version": "0.2.0",
"codegen-helpers": {
"packages": {
"elm/core": "1.0.5",
"dillonkearns/elm-form": "3.0.0",
"elm/html": "1.0.0",
"rtfeldman/elm-css": "18.0.0",
"dillonkearns/elm-pages-v3-beta": "21.0.0",
"elm/json": "1.1.3"
},
"local": [
".elm-pages/",
"app/",
"src/"
]
}
}

View File

@ -0,0 +1,3 @@
export async function hello(name) {
return `Hello ${name}!`;
}

View File

@ -1,5 +1,18 @@
import { defineConfig } from "vite";
import adapter from "elm-pages/adapter/netlify.js";
export default {
vite: defineConfig({}),
adapter,
headTagsTemplate(context) {
return `
<link rel="stylesheet" href="/style.css" />
<meta name="generator" content="elm-pages v${context.cliVersion}" />
`;
},
preloadTagForFile(file) {
// add preload directives for JS assets and font assets, etc., skip for CSS files
// this function will be called with each file that is procesed by Vite, including any files in your headTagsTemplate in your config
return !file.endsWith(".css");
},
};

View File

@ -1,60 +1,57 @@
{
"type": "application",
"source-directories": [
"app",
"src",
".elm-pages"
"../codegen"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"dillonkearns/elm-cli-options-parser": "3.2.0",
"dillonkearns/elm-pages-v3-beta": "21.0.0",
"elm/bytes": "1.0.8",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/json": "1.1.3",
"mdgriffith/elm-codegen": "3.0.0"
},
"indirect": {
"Chadtech/elm-bool-extra": "2.4.2",
"avh4/elm-color": "1.0.0",
"danfishgold/base64-bytes": "1.1.0",
"danyx23/elm-mimetype": "4.0.1",
"dillonkearns/elm-bcp47-language-tag": "1.0.1",
"dillonkearns/elm-markdown": "7.0.1",
"dillonkearns/elm-pages-v3-beta": "12.0.0",
"dillonkearns/elm-date-or-date-time": "2.0.0",
"dillonkearns/elm-form": "3.0.0",
"elm/browser": "1.0.2",
"elm/bytes": "1.0.8",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/file": "1.0.5",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/parser": "1.1.0",
"elm/random": "1.0.0",
"elm/regex": "1.0.0",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.3",
"elm-community/dict-extra": "2.4.0",
"elm-community/list-extra": "8.7.0",
"elm-community/result-extra": "2.4.0",
"jluckyiv/elm-utc-date-strings": "1.0.0",
"justinmimbs/date": "4.0.1",
"mdgriffith/elm-codegen": "2.0.0",
"miniBill/elm-codec": "2.0.0",
"noahzgordon/elm-color-extra": "1.0.2",
"robinheghan/fnv1a": "1.0.0",
"rtfeldman/elm-css": "18.0.0",
"the-sett/elm-syntax-dsl": "6.0.2",
"turboMaCk/non-empty-list-alias": "1.3.1",
"vito/elm-ansi": "10.0.1"
},
"indirect": {
"Chadtech/elm-bool-extra": "2.4.2",
"dillonkearns/elm-cli-options-parser": "3.2.0",
"dillonkearns/elm-date-or-date-time": "2.0.0",
"elm/file": "1.0.5",
"elm/random": "1.0.0",
"elm-community/basics-extra": "4.1.0",
"elm-community/list-extra": "8.7.0",
"elm-community/maybe-extra": "5.3.0",
"fredcy/elm-parseint": "2.0.1",
"jluckyiv/elm-utc-date-strings": "1.0.0",
"justinmimbs/date": "4.0.1",
"miniBill/elm-codec": "2.0.0",
"miniBill/elm-unicode": "1.0.3",
"noahzgordon/elm-color-extra": "1.0.2",
"robinheghan/fnv1a": "1.0.0",
"robinheghan/murmur3": "1.0.0",
"rtfeldman/elm-css": "18.0.0",
"rtfeldman/elm-hex": "1.0.0",
"rtfeldman/elm-iso8601-date-strings": "1.1.4",
"stil4m/elm-syntax": "7.2.9",
"stil4m/structured-writer": "1.0.3",
"the-sett/elm-pretty-printer": "3.0.0"
"the-sett/elm-pretty-printer": "3.0.0",
"the-sett/elm-syntax-dsl": "6.0.2",
"turboMaCk/non-empty-list-alias": "1.3.1",
"vito/elm-ansi": "10.0.1"
}
},
"test-dependencies": {

View File

@ -1,10 +1,13 @@
[build]
functions = "functions/"
publish = "dist/"
command = "export ELM_HOME=\"$NETLIFY_BUILD_BASE/cache/elm\" && npm install --no-optional && npm run build"
command = "mkdir bin && export PATH=\"/opt/build/repo/bin:$PATH\" && echo $PATH && curl https://static.lamdera.com/bin/linux/lamdera -o bin/lamdera && chmod a+x bin/lamdera && export ELM_HOME=\"$NETLIFY_BUILD_BASE/cache/elm\" && npm install && npm run build"
[dev]
command = "npm start"
targetPort = 1234
autoLaunch = true
framework = "#custom"
[functions]
node_bundler = "esbuild"

View File

@ -7,14 +7,14 @@
"build": "elm-pages build"
},
"devDependencies": {
"elm-codegen": "^0.2.0",
"elm-codegen": "^0.3.0",
"elm-optimize-level-2": "^0.3.5",
"elm-pages": "^3.0.0-beta.20",
"elm-review": "2.8.5",
"elm-tooling": "^1.10.0",
"vite": "^3.1.8"
"elm-pages": "^3.0.0-beta.42",
"elm-review": "^2.10.2",
"elm-tooling": "^1.14.0",
"vite": "^4.3.5"
},
"dependencies": {
"@netlify/functions": "^1.2.0"
"@netlify/functions": "^1.4.0"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 B

View File

@ -0,0 +1,7 @@
// script/custom-backend-task.ts
async function hello(name) {
return `Hello ${name}!`;
}
export {
hello
};

View File

@ -0,0 +1,3 @@
export async function hello(name) {
return `Hello ${name}!`;
}

View File

@ -0,0 +1,61 @@
{
"type": "application",
"source-directories": [
"src",
"../codegen"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"dillonkearns/elm-cli-options-parser": "3.2.0",
"dillonkearns/elm-pages-v3-beta": "21.0.0",
"elm/bytes": "1.0.8",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/json": "1.1.3",
"mdgriffith/elm-codegen": "3.0.0"
},
"indirect": {
"Chadtech/elm-bool-extra": "2.4.2",
"avh4/elm-color": "1.0.0",
"danfishgold/base64-bytes": "1.1.0",
"danyx23/elm-mimetype": "4.0.1",
"dillonkearns/elm-bcp47-language-tag": "1.0.1",
"dillonkearns/elm-date-or-date-time": "2.0.0",
"dillonkearns/elm-form": "3.0.0",
"elm/browser": "1.0.2",
"elm/file": "1.0.5",
"elm/http": "2.0.0",
"elm/parser": "1.1.0",
"elm/random": "1.0.0",
"elm/regex": "1.0.0",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.3",
"elm-community/basics-extra": "4.1.0",
"elm-community/list-extra": "8.7.0",
"elm-community/maybe-extra": "5.3.0",
"fredcy/elm-parseint": "2.0.1",
"jluckyiv/elm-utc-date-strings": "1.0.0",
"justinmimbs/date": "4.0.1",
"miniBill/elm-codec": "2.0.0",
"miniBill/elm-unicode": "1.0.3",
"noahzgordon/elm-color-extra": "1.0.2",
"robinheghan/fnv1a": "1.0.0",
"robinheghan/murmur3": "1.0.0",
"rtfeldman/elm-css": "18.0.0",
"rtfeldman/elm-hex": "1.0.0",
"rtfeldman/elm-iso8601-date-strings": "1.1.4",
"stil4m/elm-syntax": "7.2.9",
"stil4m/structured-writer": "1.0.3",
"the-sett/elm-pretty-printer": "3.0.0",
"the-sett/elm-syntax-dsl": "6.0.2",
"turboMaCk/non-empty-list-alias": "1.3.1",
"vito/elm-ansi": "10.0.1"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}

View File

@ -0,0 +1,312 @@
module AddRoute exposing (run)
import BackendTask
import Cli.Option as Option
import Cli.OptionsParser as OptionsParser
import Cli.Program as Program
import Elm
import Elm.Annotation as Type
import Elm.Case
import Elm.Declare
import Elm.Let
import Elm.Op
import Gen.BackendTask
import Gen.Effect as Effect
import Gen.FatalError
import Gen.Form as Form
import Gen.Form.FieldView as FieldView
import Gen.Html as Html
import Gen.Html.Attributes as Attr
import Gen.Json.Encode
import Gen.List
import Gen.Maybe
import Gen.Pages.Form as PagesForm
import Gen.Pages.Script
import Gen.Server.Request as Request
import Gen.Server.Response as Response
import Gen.View
import Pages.Script as Script exposing (Script)
import Scaffold.Form
import Scaffold.Route exposing (Type(..))
type alias CliOptions =
{ moduleName : List String
, fields : List ( String, Scaffold.Form.Kind )
}
run : Script
run =
Script.withCliOptions program
(\cliOptions ->
cliOptions
|> createFile
|> Script.writeFile
|> BackendTask.allowFatal
)
program : Program.Config CliOptions
program =
Program.config
|> Program.add
(OptionsParser.build CliOptions
|> OptionsParser.with (Option.requiredPositionalArg "module" |> Scaffold.Route.moduleNameCliArg)
|> OptionsParser.withRestArgs Scaffold.Form.restArgsParser
)
createFile : CliOptions -> { path : String, body : String }
createFile { moduleName, fields } =
let
formHelpers :
Maybe
{ formHandlers : Elm.Expression
, form : Elm.Expression
, declarations : List Elm.Declaration
}
formHelpers =
Scaffold.Form.provide
{ fields = fields
, elmCssView = False
, view =
\{ formState, params } ->
Elm.Let.letIn
(\fieldView ->
Elm.list
((params
|> List.map
(\{ name, kind, param } ->
fieldView (Elm.string name) param
)
)
++ [ Elm.ifThen formState.submitting
(Html.button
[ Attr.disabled True
]
[ Html.text "Submitting..."
]
)
(Html.button []
[ Html.text "Submit"
]
)
]
)
)
|> Elm.Let.fn2 "fieldView"
( "label", Type.string |> Just )
( "field", Nothing )
(\label field ->
Html.div []
[ Html.label []
[ Html.call_.text (Elm.Op.append label (Elm.string " "))
, field |> FieldView.input []
, errorsView.call formState.errors field
]
]
)
|> Elm.Let.toExpression
}
in
Scaffold.Route.serverRender
{ moduleName = moduleName
, action =
( Alias
(Type.record
(case formHelpers of
Just _ ->
[ ( "errors", Type.namedWith [ "Form" ] "ServerResponse" [ Type.string ] )
]
Nothing ->
[]
)
)
, \routeParams request ->
formHelpers
|> Maybe.map
(\justFormHelp ->
Request.formData justFormHelp.formHandlers request
|> Gen.Maybe.call_.map
(Elm.fn ( "formData", Nothing )
(\formData ->
Elm.Case.tuple formData
"response"
"parsedForm"
(\response parsedForm ->
Elm.Case.custom parsedForm
Type.int
[ Elm.Case.branch1 "Form.Valid"
( "validatedForm", Type.int )
(\validatedForm ->
Elm.Case.custom validatedForm
Type.int
[ Elm.Case.branch1 "Action"
( "parsed", Type.int )
(\parsed ->
Scaffold.Form.recordEncoder parsed fields
|> Gen.Json.Encode.encode 2
|> Gen.Pages.Script.call_.log
|> Gen.BackendTask.call_.map
(Elm.fn ( "_", Nothing )
(\_ ->
Response.render
(Elm.record
[ ( "errors", response )
]
)
)
)
)
]
)
, Elm.Case.branch2 "Form.Invalid"
( "parsed", Type.int )
( "error", Type.int )
(\_ _ ->
"Form validations did not succeed!"
|> Gen.Pages.Script.log
|> Gen.BackendTask.call_.map
(Elm.fn ( "_", Nothing )
(\_ ->
Response.render
(Elm.record
[ ( "errors", response )
]
)
)
)
)
]
)
)
)
|> Gen.Maybe.withDefault
(Gen.BackendTask.fail
(Gen.FatalError.fromString "Expected form post")
)
)
|> Maybe.withDefault
(Gen.BackendTask.succeed
(Response.render
(Elm.record [])
)
)
)
, data =
( Alias (Type.record [])
, \routeParams request ->
Gen.BackendTask.succeed
(Response.render
(Elm.record [])
)
)
, head = \app -> Elm.list []
}
|> Scaffold.Route.addDeclarations
(formHelpers
|> Maybe.map .declarations
|> Maybe.map ((::) errorsView.declaration)
|> Maybe.withDefault []
)
|> Scaffold.Route.buildWithLocalState
{ view =
\{ shared, model, app } ->
Gen.View.make_.view
{ title = moduleName |> String.join "." |> Elm.string
, body =
Elm.list
(case formHelpers of
Just justFormHelp ->
[ Html.h2 [] [ Html.text "Form" ]
, justFormHelp.form
|> PagesForm.call_.renderHtml
(Elm.list [])
(Form.options "form"
|> Form.withServerResponse
(app
|> Elm.get "action"
|> Gen.Maybe.map (Elm.get "errors")
)
)
app
]
Nothing ->
[ Html.h2 [] [ Html.text "New Page" ]
]
)
}
, update =
\{ shared, app, msg, model } ->
Elm.Case.custom msg
(Type.named [] "Msg")
[ Elm.Case.branch0 "NoOp"
(Elm.tuple model
Effect.none
)
]
, init =
\{ shared, app } ->
Elm.tuple (Elm.record []) Effect.none
, subscriptions =
\{ routeParams, path, shared, model } ->
Elm.val "Sub.none"
, model =
Alias (Type.record [])
, msg =
Custom [ Elm.variant "NoOp" ]
}
errorsView :
{ declaration : Elm.Declaration
, call : Elm.Expression -> Elm.Expression -> Elm.Expression
, callFrom : List String -> Elm.Expression -> Elm.Expression -> Elm.Expression
, value : List String -> Elm.Expression
}
errorsView =
Elm.Declare.fn2 "errorsView"
( "errors", Type.namedWith [ "Form" ] "Errors" [ Type.string ] |> Just )
( "field"
, Type.namedWith [ "Form", "Validation" ]
"Field"
[ Type.string
, Type.var "parsed"
, Type.var "kind"
]
|> Just
)
(\errors field ->
Elm.ifThen
(Gen.List.call_.isEmpty (Form.errorsForField field errors))
(Html.div [] [])
(Html.div
[]
[ Html.call_.ul (Elm.list [])
(Gen.List.call_.map
(Elm.fn ( "error", Nothing )
(\error ->
Html.li
[ Attr.style "color" "red"
]
[ Html.call_.text error
]
)
)
(Form.errorsForField field errors)
)
]
)
|> Elm.withType
(Type.namedWith [ "Html" ]
"Html"
[ Type.namedWith
[ "PagesMsg" ]
"PagesMsg"
[ Type.named [] "Msg" ]
]
)
)

View File

@ -0,0 +1,42 @@
module Stars exposing (run)
import BackendTask exposing (BackendTask)
import BackendTask.Http
import Cli.Option as Option
import Cli.OptionsParser as OptionsParser
import Cli.Program as Program
import Json.Decode as Decode
import Pages.Script as Script exposing (Script)
run : Script
run =
Script.withCliOptions program
(\{ username, repo } ->
BackendTask.Http.getJson
("https://api.github.com/repos/dillonkearns/" ++ repo)
(Decode.field "stargazers_count" Decode.int)
|> BackendTask.allowFatal
|> BackendTask.andThen
(\stars ->
Script.log (String.fromInt stars)
)
)
type alias CliOptions =
{ username : String
, repo : String
}
program : Program.Config CliOptions
program =
Program.config
|> Program.add
(OptionsParser.build CliOptions
|> OptionsParser.with
(Option.optionalKeywordArg "username" |> Option.withDefault "dillonkearns")
|> OptionsParser.with
(Option.optionalKeywordArg "repo" |> Option.withDefault "elm-pages")
)