Add route example with unit test.

This commit is contained in:
Dillon Kearns 2021-04-28 08:28:56 -07:00
parent da62ada1b9
commit 5365e4b7dd
26 changed files with 3940 additions and 0 deletions

8
examples/routing/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
node_modules/
elm-stuff/
dist/
.cache/
gen/
functions/render/elm-pages-cli.js
browser-elm.js

View File

@ -0,0 +1 @@
# README

View File

@ -0,0 +1,8 @@
{
"name": "dmy/elm-doc-preview",
"summary": "Offline documentation previewer",
"version": "5.0.0",
"exposed-modules": [
"Page"
]
}

View File

@ -0,0 +1,8 @@
{
"tools": {
"elm": "0.19.1",
"elm-format": "0.8.4",
"elm-json": "0.2.10",
"elm-test-rs": "1.0.0"
}
}

67
examples/routing/elm.json Normal file
View File

@ -0,0 +1,67 @@
{
"type": "application",
"source-directories": [
"src",
"../../src",
"gen",
"../../plugins"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"ThinkAlexandria/elm-html-in-elm": "1.0.1",
"avh4/elm-color": "1.0.0",
"billstclair/elm-xml-eeue56": "1.0.1",
"danyx23/elm-mimetype": "4.0.1",
"dillonkearns/elm-bcp47-language-tag": "1.0.1",
"dillonkearns/elm-markdown": "6.0.1",
"dillonkearns/elm-oembed": "1.0.0",
"dillonkearns/elm-rss": "1.0.1",
"dillonkearns/elm-sitemap": "1.0.1",
"dmy/elm-imf-date-time": "1.0.1",
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/regex": "1.0.0",
"elm/svg": "1.0.1",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2",
"elm-community/dict-extra": "2.4.0",
"elm-community/list-extra": "8.3.0",
"elm-community/result-extra": "2.4.0",
"elm-community/string-extra": "4.0.1",
"elm-explorations/markdown": "1.0.0",
"justinmimbs/date": "3.2.0",
"lukewestby/elm-string-interpolate": "1.0.4",
"matheus23/elm-default-tailwind-modules": "1.0.0",
"mdgriffith/elm-ui": "1.1.8",
"miniBill/elm-codec": "1.2.0",
"noahzgordon/elm-color-extra": "1.0.2",
"pablohirafuji/elm-syntax-highlight": "3.3.0",
"rtfeldman/elm-css": "16.1.1",
"rtfeldman/elm-hex": "1.0.0",
"tripokey/elm-fuzzy": "5.2.1",
"zwilias/json-decode-exploration": "6.0.0"
},
"indirect": {
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/parser": "1.1.0",
"elm/random": "1.0.0",
"fredcy/elm-parseint": "2.0.1",
"justinmimbs/time-extra": "1.1.0",
"lazamar/dict-parser": "1.0.2",
"mgold/elm-nonempty-list": "4.1.0",
"ryannhg/date-format": "2.3.0"
}
},
"test-dependencies": {
"direct": {
"elm-explorations/test": "1.2.2"
},
"indirect": {}
}
}

68
examples/routing/index.md Normal file
View File

@ -0,0 +1,68 @@
<Banner>A **statically typed** site generator</Banner>
<Boxes>
<Box>
### Pure Elm Configuration
Layouts, styles, even a full-fledged elm application.
### 📄 Type-Safe Content
Configuration, errors for broken links
</Box>
<Box>
### 🚀 `elm-pages build`
No `elm make` or `webpack` setup needed! Just one simple command.
</Box>
<Box>
### 📦 Optimized Elm Progressive Web App
Layouts, styles, even a full-fledged elm application.
### Deploy anywhere
Ship to Netlify, Github Pages, or any host that will serve up static files!
</Box>
</Boxes>
<Values>
<Value>
# No magic, just types
The magic is in how the pieces snap together. The basic platform provided is simple, letting you compose exactly what you need with types to support you.
</Value>
<Value>
# Extensible through pure elm
Behavior is shared through packages exposing simple helper functions to help you build up your data.
</Value>
<Value>
# If it compiles, it works
`elm-pages` just makes more of the things you do in your static site feel like elm. Did you misspell the name of an image asset or a link to a blog post? `elm-pages` will give you a friendly error message and some helpful suggestions.
</Value>
<Value>
# An extended elm platform
`elm-pages` is just elm, but with a broader set of primitives for declaring meta tags to improve SEO, or generate RSS feeds and other files based on your static content.
</Value>
<Value>
# Blazing fast
All you have to do is create your content and choose how to present it. Optimized images, pre-rendered pages, and a snappy lightweight single-page app all come for free.
</Value>
<Value>
# Simple
`elm-pages` gives you the smallest set of core concepts possible, and a type system to make sure all the pieces fit together just right. The rest is up to you. Rather than remember a lot of magic and special cases, you can just rely on your elm types to build what you need with a set of simple primitives.
</Value>
</Values>

2555
examples/routing/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
{
"name": "elm-pages-example",
"version": "1.0.0",
"description": "Example site built with elm-pages.",
"scripts": {
"start": "elm-pages dev",
"serve": "npm run build && http-server ./dist -a localhost -p 3000 -c-1",
"build": "elm-pages build"
},
"author": "Dillon Kearns",
"license": "BSD-3",
"devDependencies": {
"elm-oembed": "0.0.6",
"elm-pages": "file:../..",
"elm-tooling": "^1.3.0",
"http-server": "^0.11.1"
}
}

View File

@ -0,0 +1,37 @@
## elm-pages 2.0
```
elm-pages generate Projects.Username_.Repo_
```
```elm
type alias RouteParams =
{ username : String, repo : String }
template : Template RouteParams StaticData
template =
Template.noStaticData
{ head = head
, staticRoutes = StaticHttp.succeed []
}
|> Template.buildNoState { view = view }
view :
StaticPayload StaticData RouteParams
-> Document Msg
view static =
{ title = "TODO title"
, body = []
}
```
## Core Concepts
- Page Templates (`Template.*.elm`)
- `DataSource`s
- `Shared.elm`, `Site.elm`
## Page Templates
Here's another body

View File

@ -0,0 +1,23 @@
module Document exposing (Document, map, placeholder)
import Html.Styled exposing (text)
type alias Document msg =
{ title : String
, body : List (Html.Styled.Html msg)
}
map : (msg1 -> msg2) -> Document msg1 -> Document msg2
map fn doc =
{ title = doc.title
, body = List.map (Html.Styled.map fn) doc.body
}
placeholder : String -> Document msg
placeholder moduleName =
{ title = "Placeholder - " ++ moduleName
, body = [ text moduleName ]
}

View File

@ -0,0 +1,233 @@
module MarkdownRenderer exposing (renderer)
import Html.Styled as Html
import Html.Styled.Attributes as Attr exposing (css)
import Markdown.Block as Block exposing (ListItem(..), Task(..))
import Markdown.Html
import Markdown.Renderer
import SyntaxHighlight
import Tailwind.Utilities as Tw
renderer : Markdown.Renderer.Renderer (Html.Html msg)
renderer =
{ heading = heading
, paragraph = Html.p []
, thematicBreak = Html.hr [] []
, text = Html.text
, strong = \content -> Html.strong [ css [ Tw.font_bold ] ] content
, emphasis = \content -> Html.em [ css [ Tw.italic ] ] content
, blockQuote = Html.blockquote []
, codeSpan =
\content ->
Html.code
[ css
[ Tw.font_semibold
, Tw.font_medium
]
]
[ Html.text content ]
--, codeSpan = code
, link =
\{ destination } body ->
Html.a
[ Attr.href destination
, css
[ Tw.underline
]
]
body
, hardLineBreak = Html.br [] []
, image =
\image ->
case image.title of
Just _ ->
Html.img [ Attr.src image.src, Attr.alt image.alt ] []
Nothing ->
Html.img [ Attr.src image.src, Attr.alt image.alt ] []
, unorderedList =
\items ->
Html.ul []
(items
|> List.map
(\item ->
case item of
Block.ListItem task children ->
let
checkbox =
case task of
Block.NoTask ->
Html.text ""
Block.IncompleteTask ->
Html.input
[ Attr.disabled True
, Attr.checked False
, Attr.type_ "checkbox"
]
[]
Block.CompletedTask ->
Html.input
[ Attr.disabled True
, Attr.checked True
, Attr.type_ "checkbox"
]
[]
in
Html.li [] (checkbox :: children)
)
)
, orderedList =
\startingIndex items ->
Html.ol
(case startingIndex of
1 ->
[ Attr.start startingIndex ]
_ ->
[]
)
(items
|> List.map
(\itemBlocks ->
Html.li []
itemBlocks
)
)
, html = Markdown.Html.oneOf []
, codeBlock = codeBlock
--\{ body, language } ->
-- let
-- classes =
-- -- Only the first word is used in the class
-- case Maybe.map String.words language of
-- Just (actualLanguage :: _) ->
-- [ Attr.class <| "language-" ++ actualLanguage ]
--
-- _ ->
-- []
-- in
-- Html.pre []
-- [ Html.code classes
-- [ Html.text body
-- ]
-- ]
, table = Html.table []
, tableHeader = Html.thead []
, tableBody = Html.tbody []
, tableRow = Html.tr []
, strikethrough =
\children -> Html.del [] children
, tableHeaderCell =
\maybeAlignment ->
let
attrs =
maybeAlignment
|> Maybe.map
(\alignment ->
case alignment of
Block.AlignLeft ->
"left"
Block.AlignCenter ->
"center"
Block.AlignRight ->
"right"
)
|> Maybe.map Attr.align
|> Maybe.map List.singleton
|> Maybe.withDefault []
in
Html.th attrs
, tableCell =
\maybeAlignment ->
let
attrs =
maybeAlignment
|> Maybe.map
(\alignment ->
case alignment of
Block.AlignLeft ->
"left"
Block.AlignCenter ->
"center"
Block.AlignRight ->
"right"
)
|> Maybe.map Attr.align
|> Maybe.map List.singleton
|> Maybe.withDefault []
in
Html.td attrs
}
rawTextToId : String -> String
rawTextToId rawText =
rawText
|> String.split " "
|> String.join "-"
|> String.toLower
heading : { level : Block.HeadingLevel, rawText : String, children : List (Html.Html msg) } -> Html.Html msg
heading { level, rawText, children } =
(case level of
Block.H1 ->
Html.h1
Block.H2 ->
Html.h2
Block.H3 ->
Html.h3
Block.H4 ->
Html.h4
Block.H5 ->
Html.h5
Block.H6 ->
Html.h6
)
[ Attr.id (rawTextToId rawText)
, Attr.attribute "name" (rawTextToId rawText)
, css
[ Tw.font_bold
, Tw.text_2xl
, Tw.mt_8
, Tw.mb_4
]
]
children
--code : String -> Element msg
--code snippet =
-- Element.el
-- [ Element.Background.color
-- (Element.rgba255 50 50 50 0.07)
-- , Element.Border.rounded 2
-- , Element.paddingXY 5 3
-- , Font.family [ Font.typeface "Roboto Mono", Font.monospace ]
-- ]
-- (Element.text snippet)
--
--
codeBlock : { body : String, language : Maybe String } -> Html.Html msg
codeBlock details =
SyntaxHighlight.elm details.body
|> Result.map (SyntaxHighlight.toBlockHtml (Just 1))
|> Result.map Html.fromUnstyled
|> Result.withDefault (Html.pre [] [ Html.code [] [ Html.text details.body ] ])

View File

@ -0,0 +1,83 @@
module Page.Cats.Name__ exposing (Data, Model, Msg, page)
import DataSource
import Document exposing (Document)
import Element exposing (Element)
import Head
import Head.Seo as Seo
import Html.Styled exposing (text)
import Page exposing (Page, PageWithState, StaticPayload)
import Pages.ImagePath as ImagePath
import Shared
type alias Model =
()
type alias Msg =
Never
type alias RouteParams =
{ name : Maybe String }
page : Page RouteParams Data
page =
Page.prerenderedRoute
{ head = head
, routes = routes
, data = data
}
|> Page.buildNoState { view = view }
routes : DataSource.DataSource (List RouteParams)
routes =
DataSource.succeed
[ { name = Just "larry"
}
, { name = Nothing
}
]
data : RouteParams -> DataSource.DataSource Data
data routeParams =
DataSource.succeed ()
head :
StaticPayload Data RouteParams
-> List Head.Tag
head static =
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "TODO" ]
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
}
, description = "TODO"
, locale = Nothing
, title = "TODO title" -- metadata.title -- TODO
}
|> Seo.website
type alias Data =
()
view :
StaticPayload Data RouteParams
-> Document Msg
view static =
{ body =
[ text (static.routeParams.name |> Maybe.withDefault "NOTHING")
]
, title = ""
}

View File

@ -0,0 +1,63 @@
module Page.Slide exposing (Data, Model, Msg, page)
import DataSource
import Document exposing (Document)
import Head
import Head.Seo as Seo
import Page exposing (Page, PageWithState, StaticPayload)
import Pages.ImagePath as ImagePath
import Shared
type alias Model =
()
type alias Msg =
Never
type alias RouteParams =
{}
page : Page RouteParams Data
page =
Page.singleRoute
{ head = head
, data = DataSource.succeed ()
}
|> Page.buildNoState { view = view }
head :
StaticPayload Data RouteParams
-> List Head.Tag
head static =
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "TODO" ]
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
}
, description = "TODO"
, locale = Nothing
, title = "TODO title" -- metadata.title -- TODO
}
|> Seo.website
type alias Data =
()
view :
StaticPayload Data RouteParams
-> Document Msg
view static =
{ title = "TODO title"
, body = []
}

View File

@ -0,0 +1,256 @@
module Page.Slide.Number_ exposing (Data, Model, Msg, page)
import Browser.Events
import Browser.Navigation
import DataSource
import DataSource.File
import Document exposing (Document)
import Head
import Head.Seo as Seo
import Html.Styled as Html
import Html.Styled.Attributes exposing (css)
import Json.Decode as Decode
import Markdown.Block
import Markdown.Parser
import Markdown.Renderer
import MarkdownRenderer
import OptimizedDecoder
import Page exposing (Page, StaticPayload)
import Pages.ImagePath as ImagePath
import Shared
import Tailwind.Utilities as Tw
type alias Model =
()
type Msg
= OnKeyPress (Maybe Direction)
type alias RouteParams =
{ number : String }
page : Page.PageWithState RouteParams Data Model Msg
page =
Page.prerenderedRoute
{ head = head
, routes =
slideCount
|> DataSource.map
(\count ->
List.range 1 count
|> List.map String.fromInt
|> List.map RouteParams
)
, data = data
}
|> Page.buildWithLocalState
{ view = view
, init = \staticPayload -> ( (), Cmd.none )
, update =
\sharedModel static msg model ->
case msg of
OnKeyPress (Just direction) ->
let
currentSlide =
String.toInt static.routeParams.number |> Maybe.withDefault 0
nextSlide =
clamp
1
static.static.totalCount
(case direction of
Right ->
currentSlide + 1
Left ->
currentSlide - 1
)
in
( model
, sharedModel.navigationKey
|> Maybe.map
(\navKey ->
Browser.Navigation.pushUrl navKey
("/slide/"
++ String.fromInt
nextSlide
)
)
|> Maybe.withDefault Cmd.none
)
_ ->
( model, Cmd.none )
, subscriptions =
\routeParams path model ->
Browser.Events.onKeyDown keyDecoder |> Sub.map OnKeyPress
}
type Direction
= Left
| Right
keyDecoder : Decode.Decoder (Maybe Direction)
keyDecoder =
Decode.map toDirection (Decode.field "key" Decode.string)
toDirection : String -> Maybe Direction
toDirection string =
case string of
"ArrowLeft" ->
Just Left
"ArrowRight" ->
Just Right
_ ->
Nothing
data : RouteParams -> DataSource.DataSource Data
data routeParams =
DataSource.map2 Data
(slideBody routeParams)
slideCount
slideBody : RouteParams -> DataSource.DataSource (List (Html.Html Msg))
slideBody route =
DataSource.File.request
"slides.md"
(DataSource.File.body
|> OptimizedDecoder.andThen
(\rawBody ->
case rawBody |> Markdown.Parser.parse of
Ok okBlocks ->
case
okBlocks
|> markdownIndexedByHeading (route.number |> String.toInt |> Maybe.withDefault 1)
|> Markdown.Renderer.render MarkdownRenderer.renderer
of
Ok renderedBody ->
OptimizedDecoder.succeed renderedBody
Err error ->
OptimizedDecoder.fail error
Err _ ->
OptimizedDecoder.fail ""
)
)
slideCount : DataSource.DataSource Int
slideCount =
DataSource.File.request "slides.md"
(DataSource.File.body
|> OptimizedDecoder.andThen
(\rawBody ->
case rawBody |> Markdown.Parser.parse of
Ok okBlocks ->
okBlocks
|> Markdown.Block.foldl
(\block h2CountSoFar ->
case block of
Markdown.Block.Heading Markdown.Block.H2 _ ->
h2CountSoFar + 1
_ ->
h2CountSoFar
)
0
|> OptimizedDecoder.succeed
Err _ ->
OptimizedDecoder.fail ""
)
)
markdownIndexedByHeading :
Int
-> List Markdown.Block.Block
-> List Markdown.Block.Block
markdownIndexedByHeading index markdownBlocks =
Markdown.Block.foldl
(\block ( currentIndex, markdownToKeep ) ->
case block of
Markdown.Block.Heading Markdown.Block.H2 _ ->
let
newIndex =
currentIndex + 1
in
--_ ->
if newIndex == index then
( newIndex, block :: markdownToKeep )
else
( newIndex, markdownToKeep )
_ ->
if currentIndex == index then
( currentIndex, block :: markdownToKeep )
else
( currentIndex, markdownToKeep )
)
( 0, [] )
markdownBlocks
|> Tuple.second
|> List.reverse
head :
StaticPayload Data RouteParams
-> List Head.Tag
head static =
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "TODO" ]
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
}
, description = "TODO"
, locale = Nothing
, title = "TODO title" -- metadata.title -- TODO
}
|> Seo.website
type alias Data =
{ body : List (Html.Html Msg)
, totalCount : Int
}
view :
Model
-> Shared.Model
-> StaticPayload Data RouteParams
-> Document Msg
view model sharedModel static =
{ title = "TODO title"
, body =
[ Html.div
[ css
[ Tw.prose
, Tw.max_w_lg
, Tw.px_8
, Tw.py_6
]
]
(static.static.body
++ [ Html.text static.routeParams.number ]
)
]
}

View File

@ -0,0 +1,108 @@
module Shared exposing (Data, Model, Msg(..), SharedMsg(..), template)
import Browser.Navigation
import Css.Global
import DataSource
import DataSource.Http
import Document exposing (Document)
import Html exposing (Html)
import Html.Styled
import OptimizedDecoder as D
import Pages.PagePath exposing (PagePath)
import Secrets
import SharedTemplate exposing (SharedTemplate)
import Tailwind.Utilities
template : SharedTemplate Msg Model Data SharedMsg msg
template =
{ init = init
, update = update
, view = view
, data = data
, subscriptions = subscriptions
, onPageChange = Just OnPageChange
, sharedMsg = SharedMsg
}
type Msg
= OnPageChange
{ path : PagePath
, query : Maybe String
, fragment : Maybe String
}
| SharedMsg SharedMsg
type alias Data =
Int
type SharedMsg
= NoOp
type alias Model =
{ showMobileMenu : Bool
}
init :
Maybe Browser.Navigation.Key
->
Maybe
{ path :
{ path : PagePath
, query : Maybe String
, fragment : Maybe String
}
, metadata : route
}
-> ( Model, Cmd Msg )
init _ maybePagePath =
( { showMobileMenu = False }
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
OnPageChange _ ->
( { model | showMobileMenu = False }, Cmd.none )
SharedMsg globalMsg ->
( model, Cmd.none )
subscriptions : PagePath -> Model -> Sub Msg
subscriptions _ _ =
Sub.none
data : DataSource.DataSource Data
data =
DataSource.Http.get (Secrets.succeed "https://api.github.com/repos/dillonkearns/elm-pages")
(D.field "stargazers_count" D.int)
view :
Data
->
{ path : PagePath
, frontmatter : route
}
-> Model
-> (Msg -> msg)
-> Document msg
-> { body : Html msg, title : String }
view stars page model toMsg pageView =
{ body =
Html.Styled.div []
(Css.Global.global Tailwind.Utilities.globalStyles
:: pageView.body
)
|> Html.Styled.toUnstyled
, title = pageView.title
}

View File

@ -0,0 +1,46 @@
module SharedTemplate exposing (..)
import Browser.Navigation
import DataSource
import Document exposing (Document)
import Html exposing (Html)
import Pages.PagePath exposing (PagePath)
import Route exposing (Route)
type alias SharedTemplate msg sharedModel sharedData sharedMsg mappedMsg =
{ init :
Maybe Browser.Navigation.Key
->
Maybe
{ path :
{ path : PagePath
, query : Maybe String
, fragment : Maybe String
}
, metadata : Maybe Route
}
-> ( sharedModel, Cmd msg )
, update : msg -> sharedModel -> ( sharedModel, Cmd msg )
, view :
sharedData
->
{ path : PagePath
, frontmatter : Maybe Route
}
-> sharedModel
-> (msg -> mappedMsg)
-> Document mappedMsg
-> { body : Html mappedMsg, title : String }
, data : DataSource.DataSource sharedData
, subscriptions : PagePath -> sharedModel -> Sub msg
, onPageChange :
Maybe
({ path : PagePath
, query : Maybe String
, fragment : Maybe String
}
-> msg
)
, sharedMsg : sharedMsg -> msg
}

View File

@ -0,0 +1,132 @@
module Site exposing (config)
import Cloudinary
import Color
import DataSource
import Head
import MimeType
import Pages.ImagePath as ImagePath exposing (ImagePath)
import Pages.Manifest as Manifest
import Pages.Manifest.Category
import Pages.PagePath as PagePath
import Route exposing (Route)
import SiteConfig exposing (SiteConfig)
import Sitemap
config : SiteConfig Data
config =
\routes ->
{ data = data
, canonicalUrl = canonicalUrl
, manifest = manifest
, head = head
, generateFiles = generateFiles routes
}
generateFiles :
List (Maybe Route)
->
DataSource.DataSource
(List
(Result
String
{ path : List String
, content : String
}
)
)
generateFiles allRoutes =
DataSource.succeed
[ siteMap allRoutes |> Ok
]
type alias Data =
{ siteName : String
}
data : DataSource.DataSource Data
data =
DataSource.map Data
--(StaticFile.request "site-name.txt" StaticFile.body)
(DataSource.succeed "site-name")
head : Data -> List Head.Tag
head static =
[ Head.icon [ ( 32, 32 ) ] MimeType.Png (cloudinaryIcon MimeType.Png 32)
, Head.icon [ ( 16, 16 ) ] MimeType.Png (cloudinaryIcon MimeType.Png 16)
, Head.appleTouchIcon (Just 180) (cloudinaryIcon MimeType.Png 180)
, Head.appleTouchIcon (Just 192) (cloudinaryIcon MimeType.Png 192)
, Head.sitemapLink "/sitemap.xml"
]
canonicalUrl : String
canonicalUrl =
"https://elm-pages.com"
manifest : Data -> Manifest.Config
manifest static =
Manifest.init
{ name = static.siteName
, description = "elm-pages - " ++ tagline
, startUrl = PagePath.build []
, icons =
[ icon webp 192
, icon webp 512
, icon MimeType.Png 192
, icon MimeType.Png 512
]
}
|> Manifest.withShortName "elm-pages"
tagline : String
tagline =
"A statically typed site generator"
webp : MimeType.MimeImage
webp =
MimeType.OtherImage "webp"
icon :
MimeType.MimeImage
-> Int
-> Manifest.Icon
icon format width =
{ src = cloudinaryIcon format width
, sizes = [ ( width, width ) ]
, mimeType = format |> Just
, purposes = [ Manifest.IconPurposeAny, Manifest.IconPurposeMaskable ]
}
cloudinaryIcon :
MimeType.MimeImage
-> Int
-> ImagePath
cloudinaryIcon mimeType width =
Cloudinary.urlSquare "v1603234028/elm-pages/elm-pages-icon" (Just mimeType) width
siteMap :
List (Maybe Route)
-> { path : List String, content : String }
siteMap allRoutes =
allRoutes
|> List.filterMap identity
|> List.map
(\route ->
{ path = Route.routeToPath (Just route) |> String.join "/"
, lastMod = Nothing
}
)
|> Sitemap.build { siteUrl = "https://elm-pages.com" }
|> (\sitemapXmlString -> { path = [ "sitemap.xml" ], content = sitemapXmlString })

View File

@ -0,0 +1,8 @@
module SiteConfig exposing (SiteConfig)
import Pages.SiteConfig
import Route exposing (Route)
type alias SiteConfig data =
Pages.SiteConfig.SiteConfig (Maybe Route) data

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 323.141 322.95" enable-background="new 0 0 323.141 322.95" xml:space="preserve">
<g>
<polygon
fill="#F0AD00"
points="161.649,152.782 231.514,82.916 91.783,82.916"/>
<polygon
fill="#7FD13B"
points="8.867,0 79.241,70.375 232.213,70.375 161.838,0"/>
<rect
fill="#7FD13B"
x="192.99"
y="107.392"
transform="matrix(0.7071 0.7071 -0.7071 0.7071 186.4727 -127.2386)"
width="107.676"
height="108.167"/>
<polygon
fill="#60B5CC"
points="323.298,143.724 323.298,0 179.573,0"/>
<polygon
fill="#5A6378"
points="152.781,161.649 0,8.868 0,314.432"/>
<polygon
fill="#F0AD00"
points="255.522,246.655 323.298,314.432 323.298,178.879"/>
<polygon
fill="#60B5CC"
points="161.649,170.517 8.869,323.298 314.43,323.298"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub icon</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

View File

@ -0,0 +1,2 @@
<svg version="1.1" viewBox="251.0485 144.52063 56.114286 74.5" width="50px" height="74.5"><defs><linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="10%" style="stop-color:rgba(1.96%,45.88%,90.2%,1);stop-opacity:1"></stop><stop offset="100%" style="stop-color:rgba(0%,94.9%,37.65%,1);stop-opacity:1"></stop></linearGradient></defs><metadata></metadata><g id="Canvas_11" stroke="none" fill="url(#grad1)" stroke-opacity="1" fill-opacity="1" stroke-dasharray="none"><g id="Canvas_11: Layer 1"><g id="Group_38"><g id="Graphic_32"><path d="M 252.5485 146.02063 L 252.5485 217.52063 L 305.66277 217.52063 L 305.66277 161.68254 L 290.00087 146.02063 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"></path></g><g id="Line_34"><line x1="266.07286" y1="182.8279" x2="290.75465" y2="183.00997" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></line></g><g id="Line_35"><line x1="266.07286" y1="191.84156" x2="290.75465" y2="192.02363" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></line></g><g id="Line_36"><line x1="266.07286" y1="200.85522" x2="290.75465" y2="201.0373" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></line></g><g id="Line_37"><line x1="266.07286" y1="164.80058" x2="278.3874" y2="164.94049" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"></line></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
export default function (elmLoaded) {}

View File

@ -0,0 +1,79 @@
@import url("https://rsms.me/inter/inter.css");
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&display=swap");
body {
font-family: "Inter var" !important;
}
pre.elmsh {
padding: 10px;
margin: 0;
text-align: left;
overflow: auto;
height: 100%;
width: 500px;
font-size: 14px;
font-family: "IBM Plex Mono" !important;
}
code.elmsh {
padding: 0;
}
.elmsh-line:before {
content: attr(data-elmsh-lc);
display: inline-block;
text-align: right;
width: 40px;
padding: 0 20px 0 0;
opacity: 0.3;
}
.elmsh {
color: #f8f8f2;
background: #1e1e1e;
}
.elmsh-hl {
background: #4864aa;
}
.elmsh-add {
background: #003800;
}
.elmsh-del {
background: #380000;
}
.elmsh-comm {
color: #d4d4d4;
}
.elmsh1 {
color: #74b0df;
}
.elmsh2 {
color: #ce9178;
}
.elmsh3 {
color: #ff00ff;
}
.elmsh4 {
color: #4f76ac;
}
.elmsh5 {
color: #3dc9b0;
}
.elmsh6 {
color: #74b0df;
}
.elmsh7 {
color: #ce9178;
}
.elmsh-elm-ts,
.elmsh-js-dk,
.elmsh-css-p {
font-style: italic;
color: #4f76ac;
}
.elmsh-js-ce {
font-style: italic;
color: #5bb498;
}
.elmsh-css-ar-i {
font-weight: bold;
color: #ff0000;
}

View File

@ -0,0 +1,43 @@
pre.elmsh {
padding: 10px;
margin: 0;
text-align: left;
overflow: auto;
padding: 20px !important;
}
code.elmsh {
padding: 0;
}
code {
font-family: 'Roboto Mono' !important;
font-size: 20px !important;
line-height: 28px;
}
.elmsh-line:before {
/* content: attr(data-elmsh-lc); */
display: inline-block;
text-align: right;
width: 40px;
padding: 0 20px 0 0;
opacity: 0.3;
}
.elmsh {
color: #f8f8f2;
background: #000;
}
.elmsh-hl {background: #343434;}
.elmsh-add {background: #003800;}
.elmsh-del {background: #380000;}
.elmsh-comm {color: #75715e;}
.elmsh1 {color: #ae81ff;}
.elmsh2 {color: #e6db74;}
.elmsh3 {color: #66d9ef;}
.elmsh4 {color: #f92672;}
.elmsh5 {color: #a6e22e;}
.elmsh6 {color: #ae81ff;}
.elmsh7 {color: #fd971f;}

View File

@ -0,0 +1,53 @@
module RouteTest exposing (..)
import Expect
import Route
import Test exposing (Test, describe, test)
all : Test
all =
describe "routes"
[ test "test 1" <|
\() ->
--{ path = "/cats/larry" }
--{ path = "/slide" }
{ path = "/cats/larry" }
|> Route.urlToRoute
|> Expect.equal
(Route.Cats__Name__
{ name = Just "larry" }
|> Just
)
--, test "test 2" <|
-- \() ->
-- "/cats"
-- |> tryMatch
-- { pattern = "^cats(?:\\/([^/]+))?$"
-- , toRoute =
-- \matches ->
-- case matches of
-- [ name ] ->
-- Cats__Name__ { name = name } |> Just
--
-- _ ->
-- Nothing
-- }
-- |> Expect.equal (Cats__Name__ { name = Nothing } |> Just)
--, test "multiple matchers" <|
-- \() ->
-- "/slide/123"
-- |> firstMatch exampleMatchers
-- |> Expect.equal (Slide__Number_ { number = "123" } |> Just)
--, test "hardcoded routes have precedence over dynamic segments" <|
-- \() ->
-- "/post/create"
-- |> firstMatch postPrecedenceExample
-- |> Expect.equal (Post__Create {} |> Just)
--, test "dynamic segments match when they are not overshadowed by a hardcoded route" <|
-- \() ->
-- "/post/update"
-- |> firstMatch postPrecedenceExample
-- |> Expect.equal (Post__Slug_ { slug = "update" } |> Just)
]