This commit is contained in:
2023-10-24 05:23:25 +07:00
commit 7a8ce17237
33 changed files with 11927 additions and 0 deletions

26
app/Api.elm Normal file
View File

@ -0,0 +1,26 @@
module Api exposing (routes)
import ApiRoute exposing (ApiRoute)
import BackendTask exposing (BackendTask)
import FatalError exposing (FatalError)
import Html exposing (Html)
import Pages.Manifest as Manifest
import Route exposing (Route)
routes :
BackendTask FatalError (List Route)
-> (Maybe { indent : Int, newLines : Bool } -> Html Never -> String)
-> List (ApiRoute ApiRoute.Response)
routes getStaticRoutes htmlToString =
[]
manifest : Manifest.Config
manifest =
Manifest.init
{ name = "Site Name"
, description = "Description"
, startUrl = Route.Index |> Route.toPath
, icons = []
}

155
app/Effect.elm Normal file
View File

@ -0,0 +1,155 @@
module Effect exposing (Effect(..), batch, fromCmd, map, none, perform)
{-|
@docs Effect, batch, fromCmd, map, none, perform
-}
import Browser.Navigation
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
, toMsg : Result Http.Error Url -> msg
}
| Submit
{ values : FormData
, toMsg : Result Http.Error Url -> 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
None ->
None
Cmd cmd ->
Cmd (Cmd.map fn cmd)
Batch list ->
Batch (List.map (map fn) list)
GetStargazers toMsg ->
GetStargazers (toMsg >> fn)
FetchRouteData fetchInfo ->
FetchRouteData
{ data = fetchInfo.data
, toMsg = fetchInfo.toMsg >> fn
}
Submit fetchInfo ->
Submit
{ values = fetchInfo.values
, toMsg = fetchInfo.toMsg >> fn
}
SetField info ->
SetField info
SubmitFetcher fetcher ->
fetcher
|> Pages.Fetcher.map fn
|> SubmitFetcher
{-| -}
perform :
{ fetchRouteData :
{ data : Maybe FormData
, toMsg : Result Http.Error Url -> pageMsg
}
-> Cmd msg
, submit :
{ values : FormData
, toMsg : Result Http.Error Url -> pageMsg
}
-> Cmd msg
, runFetcher :
Pages.Fetcher.Fetcher pageMsg
-> Cmd msg
, fromPageMsg : pageMsg -> msg
, key : Browser.Navigation.Key
, setField : { formId : String, name : String, value : String } -> Cmd msg
}
-> Effect pageMsg
-> Cmd msg
perform ({ fromPageMsg, key } as helpers) effect =
case effect of
None ->
Cmd.none
Cmd cmd ->
Cmd.map fromPageMsg cmd
SetField info ->
helpers.setField info
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
Submit record ->
helpers.submit record
SubmitFetcher record ->
helpers.runFetcher record
type alias FormData =
{ fields : List ( String, String )
, method : Form.Method
, action : String
, id : Maybe String
}

81
app/ErrorPage.elm Normal file
View File

@ -0,0 +1,81 @@
module ErrorPage exposing (ErrorPage(..), Model, Msg, head, init, internalError, notFound, statusCode, update, view)
import Effect exposing (Effect)
import Head
import Html.Styled as Html
import Html.Styled.Events exposing (onClick)
import View exposing (View)
type Msg
= Increment
type alias Model =
{ count : Int
}
init : ErrorPage -> ( Model, Effect Msg )
init errorPage =
( { count = 0 }
, Effect.none
)
update : ErrorPage -> Msg -> Model -> ( Model, Effect Msg )
update errorPage msg model =
case msg of
Increment ->
( { model | count = model.count + 1 }, Effect.none )
head : ErrorPage -> List Head.Tag
head errorPage =
[]
type ErrorPage
= NotFound
| InternalError String
notFound : ErrorPage
notFound =
NotFound
internalError : String -> ErrorPage
internalError =
InternalError
view : ErrorPage -> Model -> View Msg
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 = "This is a NotFound Error"
}
statusCode : ErrorPage -> number
statusCode error =
case error of
NotFound ->
404
InternalError _ ->
500

145
app/Route/Blog/Slug_.elm Normal file
View File

@ -0,0 +1,145 @@
module Route.Blog.Slug_ exposing (ActionData, Data, Model, Msg, route)
import Article
import BackendTask exposing (BackendTask)
import Date exposing (Date)
import FatalError exposing (FatalError)
import Head
import Head.Seo as Seo
import Html.Styled exposing (..)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Extra
import Pages.Url
import PagesMsg exposing (PagesMsg)
import RouteBuilder exposing (App, StatelessRoute)
import Shared
import View exposing (View)
import Markdown.Block
import Markdown.Renderer
import MarkdownCodec
import TailwindMarkdownRenderer
import Tailwind.Utilities as Tw
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 =
Article.blogPostsGlob
|> BackendTask.map
(List.map
(\globData ->
{ slug = globData.slug }
)
)
type alias Data =
{ metadata : ArticleMetadata
, body : List Markdown.Block.Block
}
type alias ActionData =
{}
data : RouteParams -> BackendTask FatalError Data
data routeParams =
MarkdownCodec.withFrontmatter Data
frontmatterDecoder
TailwindMarkdownRenderer.renderer
("content/blog/" ++ routeParams.slug ++ ".md")
type alias ArticleMetadata =
{ title : String
, description : String
, published : Date
-- , image : Pages.Url.Url
, draft : Bool
}
frontmatterDecoder : Decoder ArticleMetadata
frontmatterDecoder =
Decode.map4 ArticleMetadata
(Decode.field "title" Decode.string)
(Decode.field "description" Decode.string)
(Decode.field "published"
(Decode.string
|> Decode.andThen
(\isoString ->
Date.fromIsoString isoString
|> Json.Decode.Extra.fromResult
)
)
)
-- (Decode.oneOf
-- [ Decode.field "image" imageDecoder
-- , Decode.field "unsplash" UnsplashImage.decoder |> Decode.map UnsplashImage.imagePath
-- ]
-- )
(Decode.field "draft" Decode.bool
|> Decode.maybe
|> Decode.map (Maybe.withDefault False)
)
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 = "title"
, body =
(app.data.body
|> Markdown.Renderer.render TailwindMarkdownRenderer.renderer
|> Result.withDefault []
|> processReturn
)
}
processReturn : List (Html Msg) -> List (Html (PagesMsg Msg))
processReturn =
List.map (Html.Styled.map (PagesMsg.fromMsg))

94
app/Route/Index.elm Normal file
View File

@ -0,0 +1,94 @@
module Route.Index exposing (ActionData, Data, Model, Msg, route)
import BackendTask exposing (BackendTask)
import FatalError exposing (FatalError)
import Head
import Head.Seo as Seo
import Html.Styled as Html
import Link exposing (Link)
import Pages.Url
import PagesMsg exposing (PagesMsg)
import UrlPath
import Route
import RouteBuilder exposing (App, StatelessRoute)
import Shared
import View exposing (View)
type alias Model =
{}
type alias Msg =
()
type alias RouteParams =
{}
type alias Data =
{ message : String
}
type alias ActionData =
{}
route : StatelessRoute RouteParams Data ActionData
route =
RouteBuilder.single
{ head = head
, data = data
}
|> RouteBuilder.buildNoState { view = view }
data : BackendTask FatalError Data
data =
BackendTask.succeed Data
|> BackendTask.andMap
(BackendTask.succeed "Hello!")
head :
App Data ActionData RouteParams
-> List Head.Tag
head app =
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = [ "images", "icon-png.png" ] |> UrlPath.join |> Pages.Url.fromPath
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
}
, description = "Welcome to elm-pages!"
, locale = Nothing
, title = "elm-pages is running"
}
|> Seo.website
view :
App Data ActionData RouteParams
-> Shared.Model
-> View (PagesMsg Msg)
view app shared =
{ title = "elm-pages is running"
, body =
[ Html.h1 [] [ Html.text "elm-pages is up and running!" ]
, Html.p []
[ Html.text <| "The message is: " ++ app.data.message
]
, Link.link (Link.internal (Route.Blog__Slug_ { slug = "a" })) [] [ Html.text "My blog post" ]
]
|> processReturn
}
processReturn : List (Html.Html Msg) -> List (Html.Html (PagesMsg Msg))
processReturn =
List.map (Html.map (PagesMsg.fromMsg))

135
app/Shared.elm Normal file
View File

@ -0,0 +1,135 @@
module Shared exposing (Data, Model, Msg(..), SharedMsg(..), template)
import BackendTask exposing (BackendTask)
import Effect exposing (Effect)
import FatalError exposing (FatalError)
import Html exposing (Html)
import Html.Styled
import Html.Styled.Events
import Pages.Flags
import Pages.PageUrl exposing (PageUrl)
import UrlPath exposing (UrlPath)
import Route exposing (Route)
import SharedTemplate exposing (SharedTemplate)
import View exposing (View)
template : SharedTemplate Msg Model Data msg
template =
{ init = init
, update = update
, view = view
, data = data
, subscriptions = subscriptions
, onPageChange = Nothing
}
type Msg
= SharedMsg SharedMsg
| MenuClicked
type alias Data =
()
type SharedMsg
= NoOp
type alias Model =
{ showMenu : Bool
}
init :
Pages.Flags.Flags
->
Maybe
{ path :
{ path : UrlPath
, query : Maybe String
, fragment : Maybe String
}
, metadata : route
, pageUrl : Maybe PageUrl
}
-> ( Model, Effect Msg )
init flags maybePagePath =
( { showMenu = False }
, Effect.none
)
update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
case msg of
SharedMsg globalMsg ->
( model, Effect.none )
MenuClicked ->
( { model | showMenu = not model.showMenu }, Effect.none )
subscriptions : UrlPath -> Model -> Sub Msg
subscriptions _ _ =
Sub.none
data : BackendTask FatalError Data
data =
BackendTask.succeed ()
view :
Data
->
{ path : UrlPath
, route : Maybe Route
}
-> Model
-> (Msg -> msg)
-> View msg
-> { body : List (Html msg), title : String }
view tableOfContents page model toMsg pageView =
{ body =
[
-- ((View.Header.view ToggleMobileMenu 123 page.path
-- |> Html.Styled.map toMsg
-- )
-- :: TableOfContents.view model.showMobileMenu False Nothing tableOfContents
pageView.body
-- )
|> Html.Styled.div []
|> Html.Styled.toUnstyled
]
, title = pageView.title
}
-- view sharedData page model toMsg pageView =
-- { body =
-- [ Html.Styled.nav []
-- [ Html.Styled.button
-- [ Html.Styled.Events.onClick MenuClicked ]
-- [ Html.Styled.text
-- (if model.showMenu then
-- "Close Menu"
-- else
-- "Open Menu"
-- )
-- ]
-- , if model.showMenu then
-- Html.Styled.ul []
-- [ Html.Styled.li [] [ Html.Styled.text "Menu item 1" ]
-- , Html.Styled.li [] [ Html.Styled.text "Menu item 2" ]
-- ]
-- else
-- Html.Styled.text ""
-- ]
-- |> Html.Styled.map toMsg
-- , Html.Styled.main_ [] pageView.body
-- ]
-- , title = pageView.title
-- }

21
app/Site.elm Normal file
View File

@ -0,0 +1,21 @@
module Site exposing (config)
import BackendTask exposing (BackendTask)
import FatalError exposing (FatalError)
import Head
import SiteConfig exposing (SiteConfig)
config : SiteConfig
config =
{ canonicalUrl = "https://elm-pages.com"
, head = head
}
head : BackendTask FatalError (List Head.Tag)
head =
[ Head.metaName "viewport" (Head.raw "width=device-width,initial-scale=1")
, Head.sitemapLink "/sitemap.xml"
]
|> BackendTask.succeed

24
app/View.elm Normal file
View File

@ -0,0 +1,24 @@
module View exposing (View, map)
{-|
@docs View, map
-}
import Html.Styled as 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
, body = List.map (Html.map fn) doc.body
}