Add Pages.Url and replace ImagePath with Pages.Url.Url type.

This commit is contained in:
Dillon Kearns 2021-05-23 15:11:46 -07:00
parent 231d38cc69
commit 48dabe8673
20 changed files with 127 additions and 83 deletions

View File

@ -10,7 +10,7 @@
"Path",
"OptimizedDecoder",
"OptimizedDecoder.Pipeline",
"Pages.ImagePath",
"Pages.Url",
"DataSource",
"DataSource.Glob",
"DataSource.Http",

View File

@ -6,7 +6,7 @@ import DataSource.File as StaticFile
import DataSource.Glob as Glob
import Date exposing (Date)
import OptimizedDecoder
import Pages.ImagePath exposing (ImagePath)
import Pages.Url exposing (Url)
import Route
@ -59,7 +59,7 @@ type alias ArticleMetadata =
{ title : String
, description : String
, published : Date
, image : ImagePath
, image : Url
, draft : Bool
}
@ -89,7 +89,7 @@ frontmatterDecoder =
)
imageDecoder : OptimizedDecoder.Decoder ImagePath
imageDecoder : OptimizedDecoder.Decoder Url
imageDecoder =
OptimizedDecoder.string
|> OptimizedDecoder.map (\cloudinaryAsset -> Cloudinary.url cloudinaryAsset Nothing 800)

View File

@ -3,12 +3,12 @@ module Data.Author exposing (Author, all, decoder, dillon)
import Cloudinary
import Json.Decode as Decode exposing (Decoder)
import List.Extra
import Pages.ImagePath exposing (ImagePath)
import Pages.Url exposing (Url)
type alias Author =
{ name : String
, avatar : ImagePath
, avatar : Url
, bio : String
}

View File

@ -9,6 +9,8 @@ import Html.Styled exposing (..)
import Html.Styled.Attributes as Attr exposing (css)
import Page exposing (DynamicContext, PageWithState, StaticPayload)
import Pages.ImagePath as ImagePath
import Pages.Url
import Path
import Route exposing (Route)
import Shared
import SiteOld
@ -180,7 +182,7 @@ head staticPayload =
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "images", "icon-png.png" ]
{ url = [ "images", "icon-png.png" ] |> Path.join |> Pages.Url.fromPath
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing

View File

@ -2,7 +2,6 @@ module Page.Blog.Slug_ exposing (Data, Model, Msg, page, toRssItem)
import Article
import Cloudinary
import Css
import Data.Author as Author exposing (Author)
import DataSource
import DataSource.File as StaticFile
@ -16,7 +15,7 @@ import Markdown.Parser
import Markdown.Renderer
import OptimizedDecoder
import Page exposing (Page, PageWithState, StaticPayload)
import Pages.ImagePath as ImagePath exposing (ImagePath)
import Pages.Url
import Path
import Rss
import SiteOld
@ -39,16 +38,6 @@ type alias RouteParams =
{ slug : String }
type alias BlogPost =
{ title : String
, description : String
, published : Date
, author : Author
, image : ImagePath
, draft : Bool
}
page : Page RouteParams Data
page =
Page.prerenderedRoute
@ -138,7 +127,7 @@ authorView author static =
]
]
[ img
[ Attr.src (author.avatar |> ImagePath.toString)
[ Attr.src (author.avatar |> Pages.Url.toString)
, css
[ Tw.rounded_full
, Tw.h_10
@ -198,7 +187,7 @@ head static =
, author = StructuredData.person { name = Author.dillon.name }
, publisher = StructuredData.person { name = Author.dillon.name }
, url = SiteOld.canonicalUrl ++ Path.toAbsolute static.path
, imageUrl = SiteOld.canonicalUrl ++ "/" ++ ImagePath.toString metadata.image
, imageUrl = metadata.image
, datePublished = Date.toIsoString metadata.published
, mainEntityOfPage =
StructuredData.softwareSourceCode
@ -262,7 +251,7 @@ type alias ArticleMetadata =
{ title : String
, description : String
, published : Date
, image : ImagePath
, image : Pages.Url.Url
, draft : Bool
}
@ -288,7 +277,7 @@ frontmatterDecoder =
)
imageDecoder : OptimizedDecoder.Decoder ImagePath
imageDecoder : OptimizedDecoder.Decoder Pages.Url.Url
imageDecoder =
OptimizedDecoder.string
|> OptimizedDecoder.map (\cloudinaryAsset -> Cloudinary.url cloudinaryAsset Nothing 800)

View File

@ -19,6 +19,7 @@ import NextPrevious
import OptimizedDecoder
import Page exposing (Page, PageWithState, StaticPayload)
import Pages.ImagePath as ImagePath
import Pages.Url
import Shared
import TableOfContents
import Tailwind.Breakpoints as Bp
@ -169,7 +170,7 @@ head static =
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "TODO" ]
{ url = Pages.Url.external "TODO"
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing

View File

@ -8,7 +8,8 @@ import Html.Styled exposing (..)
import Html.Styled.Attributes as Attr exposing (css)
import Link
import Page exposing (Page, StaticPayload)
import Pages.ImagePath as ImagePath
import Pages.Url
import Path
import Route exposing (Route)
import SiteOld
import Svg.Styled exposing (path, svg)
@ -72,7 +73,7 @@ head static =
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "images", "icon-png.png" ]
{ url = [ "images", "icon-png.png" ] |> Path.join |> Pages.Url.fromPath
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing

View File

@ -11,6 +11,8 @@ import Html.Styled.Attributes exposing (css)
import OptimizedDecoder
import Page exposing (Page, PageWithState, StaticPayload)
import Pages.ImagePath as ImagePath
import Pages.Url
import Path
import Secrets
import Tailwind.Utilities as Tw
import View exposing (View)
@ -116,7 +118,7 @@ head static =
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "TODO" ]
{ url = [ "images", "icon-png.png" ] |> Path.join |> Pages.Url.fromPath
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing

View File

@ -7,7 +7,8 @@ import Head.Seo as Seo
import Html.Styled exposing (..)
import Html.Styled.Attributes as Attr exposing (css, href)
import Page exposing (PageWithState, StaticPayload)
import Pages.ImagePath as ImagePath
import Pages.Url
import Path
import Showcase
import Tailwind.Breakpoints as Bp
import Tailwind.Utilities as Tw
@ -86,7 +87,7 @@ head staticPayload =
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "images", "icon-png.png" ]
{ url = [ "images", "icon-png.png" ] |> Path.join |> Pages.Url.fromPath
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing

View File

@ -8,6 +8,8 @@ import Html.Styled as Html
import OptimizedDecoder
import Page exposing (Page, PageWithState, StaticPayload)
import Pages.ImagePath as ImagePath
import Pages.Url
import Path
import Secrets
import Shared
import View exposing (View)
@ -53,7 +55,7 @@ head static =
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "images", "icon-png.png" ]
{ url = [ "images", "icon-png.png" ] |> Path.join |> Pages.Url.fromPath
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing

View File

@ -4,9 +4,8 @@ import Cloudinary
import DataSource exposing (DataSource)
import Head
import MimeType
import Pages.ImagePath exposing (ImagePath)
import Pages.Manifest as Manifest
import Pages.PagePath as PagePath
import Pages.Url
import Route
import SiteConfig exposing (SiteConfig)
@ -90,6 +89,6 @@ icon format width =
cloudinaryIcon :
MimeType.MimeImage
-> Int
-> ImagePath
-> Pages.Url.Url
cloudinaryIcon mimeType width =
Cloudinary.urlSquare "v1603234028/elm-pages/elm-pages-icon" (Just mimeType) width

View File

@ -32,7 +32,7 @@ function fileContentWithParams(pageModuleName) {
return `module Page.${pageModuleName} exposing (Model, Msg, Data, page)
import View exposing (View)
import Pages.ImagePath as ImagePath
import Pages.Url
import Head
import Head.Seo as Seo
import DataSource exposing (DataSource)
@ -79,7 +79,7 @@ head static =
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "TODO" ]
{ url = Pages.Url.external "TODO"
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
@ -110,7 +110,7 @@ function fileContentWithoutParams(pageModuleName) {
return `module Page.${pageModuleName} exposing (Model, Msg, Data, page)
import View exposing (View)
import Pages.ImagePath as ImagePath
import Pages.Url
import Head
import Head.Seo as Seo
import DataSource exposing (DataSource)
@ -151,7 +151,7 @@ head static =
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "TODO" ]
{ url = Pages.Url.external "TODO"
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing

View File

@ -5,7 +5,7 @@ import View exposing (View)
import Head
import Head.Seo as Seo
import Page exposing (Page, StaticPayload)
import Pages.ImagePath as ImagePath
import Pages.Url
type alias Model =
@ -42,7 +42,7 @@ head static =
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = ImagePath.build [ "TODO" ]
{ url = Pages.Url.external "TODO"
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing

View File

@ -1,14 +1,14 @@
module Cloudinary exposing (url, urlSquare)
import MimeType
import Pages.ImagePath as ImagePath exposing (ImagePath)
import Pages.Url
url :
String
-> Maybe MimeType.MimeImage
-> Int
-> ImagePath
-> Pages.Url.Url
url asset format width =
let
base =
@ -36,14 +36,14 @@ url asset format width =
]
|> String.join ","
in
ImagePath.external (base ++ "/" ++ transforms ++ "/" ++ asset)
Pages.Url.external (base ++ "/" ++ transforms ++ "/" ++ asset)
urlSquare :
String
-> Maybe MimeType.MimeImage
-> Int
-> ImagePath
-> Pages.Url.Url
urlSquare asset format width =
let
base =
@ -72,4 +72,4 @@ urlSquare asset format width =
]
|> String.join ","
in
ImagePath.external (base ++ "/" ++ transforms ++ "/" ++ asset)
Pages.Url.external (base ++ "/" ++ transforms ++ "/" ++ asset)

View File

@ -3,9 +3,10 @@ module Head exposing
, rssLink, sitemapLink, rootLanguage
, structuredData
, AttributeValue
, currentPageFullUrl, fullImageUrl, fullPageUrl, raw
, currentPageFullUrl, raw
, appleTouchIcon, icon
, toJson, canonicalLink
, urlAttribute
)
{-| This module contains low-level functions for building up
@ -46,9 +47,8 @@ writing a plugin package to extend `elm-pages`.
import Json.Encode
import LanguageTag exposing (LanguageTag)
import MimeType
import Pages.ImagePath as ImagePath exposing (ImagePath)
import Pages.Internal.String as String
import Path exposing (Path)
import Pages.Url
{-| Values that can be passed to the generated `Pages.application` config
@ -169,16 +169,9 @@ raw value =
{-| Create an `AttributeValue` from an `ImagePath`.
-}
fullImageUrl : ImagePath -> AttributeValue
fullImageUrl value =
FullImageUrl value
{-| Create an `AttributeValue` from a `PagePath`.
-}
fullPageUrl : Path -> AttributeValue
fullPageUrl value =
FullUrl (Path.toAbsolute value)
urlAttribute : Pages.Url.Url -> AttributeValue
urlAttribute value =
FullUrl value
{-| Create an `AttributeValue` representing the current page's full url.
@ -197,8 +190,7 @@ currentPageFullUrl =
-}
type AttributeValue
= Raw String
| FullUrl String
| FullImageUrl ImagePath
| FullUrl Pages.Url.Url
| FullUrlToCurrentPage
@ -241,8 +233,8 @@ rssLink url =
{-| -}
icon : List ( Int, Int ) -> MimeType.MimeImage -> ImagePath -> Tag
icon sizes imageMimeType image =
icon : List ( Int, Int ) -> MimeType.MimeImage -> Pages.Url.Url -> Tag
icon sizes imageMimeType imageUrl =
-- TODO allow "any" for sizes value
[ ( "rel", raw "icon" |> Just )
, ( "sizes"
@ -252,7 +244,7 @@ icon sizes imageMimeType image =
|> Maybe.map raw
)
, ( "type", imageMimeType |> MimeType.Image |> MimeType.toString |> raw |> Just )
, ( "href", fullImageUrl image |> Just )
, ( "href", urlAttribute imageUrl |> Just )
]
|> filterMaybeValues
|> node "link"
@ -275,15 +267,15 @@ If a size is provided, it will be turned into square dimensions as per the recom
Images must be png's, and non-transparent images are recommended. Current recommended dimensions are 180px and 192px.
-}
appleTouchIcon : Maybe Int -> ImagePath -> Tag
appleTouchIcon maybeSize image =
appleTouchIcon : Maybe Int -> Pages.Url.Url -> Tag
appleTouchIcon maybeSize imageUrl =
[ ( "rel", raw "apple-touch-icon" |> Just )
, ( "sizes"
, maybeSize
|> Maybe.map (\size -> sizesToString [ ( size, size ) ])
|> Maybe.map raw
)
, ( "href", fullImageUrl image |> Just )
, ( "href", urlAttribute imageUrl |> Just )
]
|> filterMaybeValues
|> node "link"
@ -437,14 +429,11 @@ encodeProperty canonicalSiteUrl currentPagePath ( name, value ) =
Raw rawValue ->
Json.Encode.list Json.Encode.string [ name, rawValue ]
FullUrl urlPath ->
Json.Encode.list Json.Encode.string [ name, joinPaths canonicalSiteUrl urlPath ]
FullUrlToCurrentPage ->
Json.Encode.list Json.Encode.string [ name, joinPaths canonicalSiteUrl currentPagePath ]
FullImageUrl imagePath ->
Json.Encode.list Json.Encode.string [ name, ImagePath.toAbsoluteUrl canonicalSiteUrl imagePath ]
FullUrl url ->
Json.Encode.list Json.Encode.string [ name, Pages.Url.toAbsoluteUrl canonicalSiteUrl url ]
joinPaths : String -> String -> String

View File

@ -51,7 +51,7 @@ with the `head` function that you pass to your Pages config (`Pages.application`
import Head
import Head.Twitter as Twitter
import Pages.ImagePath exposing (ImagePath)
import Pages.Url
{-| Will be displayed as a large card in twitter
@ -408,7 +408,7 @@ type alias MimeType =
{-| See <https://ogp.me/#structured>
-}
type alias Image =
{ url : ImagePath
{ url : Pages.Url.Url
, alt : String
, dimensions : Maybe { width : Int, height : Int }
, mimeType : Maybe MimeType
@ -417,8 +417,8 @@ type alias Image =
tagsForImage : Image -> List ( String, Maybe Head.AttributeValue )
tagsForImage image =
[ ( "og:image", Just (Head.fullImageUrl image.url) )
, ( "og:image:secure_url", Just (Head.fullImageUrl image.url) )
[ ( "og:image", Just (Head.urlAttribute image.url) )
, ( "og:image:secure_url", Just (Head.urlAttribute image.url) )
, ( "og:image:alt", image.alt |> Head.raw |> Just )
, ( "og:image:width", image.dimensions |> Maybe.map .width |> Maybe.map String.fromInt |> Maybe.map Head.raw )
, ( "og:image:height", image.dimensions |> Maybe.map .height |> Maybe.map String.fromInt |> Maybe.map Head.raw )

View File

@ -1,7 +1,7 @@
module Head.Twitter exposing (SummarySize(..), TwitterCard(..), rawTags)
import Head
import Pages.ImagePath exposing (ImagePath)
import Pages.Url
type SummarySize
@ -10,7 +10,7 @@ type SummarySize
type alias Image =
{ url : ImagePath
{ url : Pages.Url.Url
, alt : String
}
@ -59,7 +59,7 @@ rawTags card =
[ ( "twitter:title", details.title |> Head.raw |> Just )
, ( "twitter:site", details.siteUser |> Maybe.map Head.raw )
, ( "twitter:description", details.description |> Maybe.map Head.raw )
, ( "twitter:image", details.image |> Maybe.map .url |> Maybe.map Head.fullImageUrl )
, ( "twitter:image", details.image |> Maybe.map .url |> Maybe.map Head.urlAttribute )
, ( "twitter:image:alt", details.image |> Maybe.map .alt |> Maybe.map Head.raw )
]
@ -67,7 +67,7 @@ rawTags card =
[ ( "twitter:title", details.title |> Head.raw |> Just )
, ( "twitter:site", details.siteUser |> Head.raw |> Just )
, ( "twitter:description", details.description |> Maybe.map Head.raw )
, ( "twitter:image", details.image |> Maybe.map .url |> Maybe.map Head.fullImageUrl )
, ( "twitter:image", details.image |> Maybe.map .url |> Maybe.map Head.urlAttribute )
, ( "twitter:image:alt", details.image |> Maybe.map .alt |> Maybe.map Head.raw )
, ( "twitter:app:name:iphone", details.appNameIphone |> Maybe.map Head.raw )
, ( "twitter:app:name:ipad", details.appNameIpad |> Maybe.map Head.raw )
@ -85,7 +85,7 @@ rawTags card =
[ ( "twitter:title", details.title |> Head.raw |> Just )
, ( "twitter:site", details.siteUser |> Head.raw |> Just )
, ( "twitter:description", details.description |> Maybe.map Head.raw )
, ( "twitter:image", Just (Head.fullImageUrl details.image.url) )
, ( "twitter:image", Just (Head.urlAttribute details.image.url) )
, ( "twitter:image:alt", details.image.alt |> Head.raw |> Just )
]
)

View File

@ -61,6 +61,7 @@ import LanguageTag.Language
import MimeType
import Pages.ImagePath as ImagePath exposing (ImagePath)
import Pages.Manifest.Category as Category exposing (Category)
import Pages.Url
import Path exposing (Path)
@ -237,7 +238,7 @@ type alias Config =
{-| <https://developer.mozilla.org/en-US/docs/Web/Manifest/icons>
-}
type alias Icon =
{ src : ImagePath
{ src : Pages.Url.Url
, sizes : List ( Int, Int )
, mimeType : Maybe MimeType.MimeImage
, purposes : List IconPurpose
@ -271,7 +272,7 @@ displayModeToAttribute displayMode =
encodeIcon : String -> Icon -> Encode.Value
encodeIcon canonicalSiteUrl icon =
encodeMaybeObject
[ ( "src", icon.src |> ImagePath.toAbsoluteUrl canonicalSiteUrl |> Encode.string |> Just )
[ ( "src", icon.src |> Pages.Url.toAbsoluteUrl canonicalSiteUrl |> Encode.string |> Just )
, ( "type", icon.mimeType |> Maybe.map MimeType.Image |> Maybe.map MimeType.toString |> Maybe.map Encode.string )
, ( "sizes", icon.sizes |> nonEmptyList |> Maybe.map sizesString |> Maybe.map Encode.string )
, ( "purpose", icon.purposes |> nonEmptyList |> Maybe.map purposesString |> Maybe.map Encode.string )

56
src/Pages/Url.elm Normal file
View File

@ -0,0 +1,56 @@
module Pages.Url exposing (Url, external, fromPath, toAbsoluteUrl, toString)
{-| Some of the `elm-pages` APIs will take internal URLs and ensure that they have the `canonicalSiteUrl` prepended.
That's the purpose for this type. If you have an external URL, like `Pages.Url.external "https://google.com"`,
then the canonicalUrl will not be prepended when it is used in a head tag.
If you refer to a local page, like `Route.Index {} |> Route.toPath |> Pages.Url.fromPath`, or `Pages.Url.fromPath`
-}
import Pages.Internal.String as String
import Path exposing (Path)
type Url
= Internal String
| External String
{-| -}
fromPath : Path -> Url
fromPath path =
path |> Path.toAbsolute |> Internal
{-| -}
external : String -> Url
external externalUrl =
External externalUrl
{-| -}
toString : Url -> String
toString path =
case path of
Internal rawPath ->
rawPath
External url ->
url
toAbsoluteUrl : String -> Url -> String
toAbsoluteUrl canonicalSiteUrl url =
case url of
External externalUrl ->
externalUrl
Internal internalUrl ->
join canonicalSiteUrl internalUrl
join : String -> String -> String
join base path =
String.chopEnd "/" base ++ "/" ++ String.chopStart "/" path

View File

@ -1,6 +1,7 @@
module StructuredData exposing (..)
import Json.Encode as Encode
import Pages.Url
{-| <https://schema.org/SoftwareSourceCode>
@ -53,7 +54,7 @@ article :
, author : StructuredData { authorMemberOf | personOrOrganization : () } authorPossibleFields
, publisher : StructuredData { publisherMemberOf | personOrOrganization : () } publisherPossibleFields
, url : String
, imageUrl : String
, imageUrl : Pages.Url.Url
, datePublished : String
, mainEntityOfPage : Encode.Value
}
@ -64,7 +65,7 @@ article info =
, ( "@type", Encode.string "Article" )
, ( "headline", Encode.string info.title )
, ( "description", Encode.string info.description )
, ( "image", Encode.string info.imageUrl )
, ( "image", Encode.string (Pages.Url.toString info.imageUrl) )
, ( "author", encode info.author )
, ( "publisher", encode info.publisher )
, ( "url", Encode.string info.url )