{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Rib.Extra.OpenGraph
( OpenGraph (..),
OGType (..),
Article (..),
)
where
import Data.Time (UTCTime)
import Data.Time.ISO8601 (formatISO8601)
import Lucid
import Lucid.Base (makeAttribute)
import Relude
import qualified Text.URI as URI
data OpenGraph = OpenGraph
{ _openGraph_title :: Text,
_openGraph_url :: Maybe URI.URI,
_openGraph_author :: Maybe Text,
_openGraph_description :: Maybe Text,
_openGraph_siteName :: Text,
_openGraph_type :: Maybe OGType,
_openGraph_image :: Maybe URI.URI
}
deriving (Eq, Show)
instance ToHtml OpenGraph where
toHtmlRaw = toHtml
toHtml OpenGraph {..} = do
meta' "author" `mapM_` _openGraph_author
meta' "description" `mapM_` _openGraph_description
requireAbsolute "OGP URL" (\uri -> link_ [rel_ "canonical", href_ uri]) `mapM_` _openGraph_url
metaOg "title" _openGraph_title
metaOg "site_name" _openGraph_siteName
toHtml `mapM_` _openGraph_type
requireAbsolute "OGP image URL" (metaOg "image") `mapM_` _openGraph_image
where
meta' k v = meta_ [name_ k, content_ v]
requireAbsolute description f uri =
if isJust (URI.uriScheme uri)
then f $ URI.render uri
else error $ description <> " must be absolute. this URI is not: " <> URI.render uri
data OGType
= OGType_Article Article
| OGType_Website
deriving (Eq, Show)
instance ToHtml OGType where
toHtmlRaw = toHtml
toHtml = \case
OGType_Article article -> do
metaOg "type" "article"
toHtml article
OGType_Website -> do
metaOg "type" "website"
data Article = Article
{ _article_section :: Maybe Text,
_article_modifiedTime :: Maybe UTCTime,
_article_publishedTime :: Maybe UTCTime,
_article_expirationTime :: Maybe UTCTime,
_article_tag :: [Text]
}
deriving (Eq, Show)
instance ToHtml Article where
toHtmlRaw = toHtml
toHtml Article {..} = do
metaOg "article:section" `mapM_` _article_section
metaOgTime "article:modified_time" `mapM_` _article_modifiedTime
metaOgTime "article:published_time" `mapM_` _article_publishedTime
metaOgTime "article:expiration_time" `mapM_` _article_expirationTime
metaOg "article:tag" `mapM_` _article_tag
where
metaOgTime k t =
metaOg k $ toText $ formatISO8601 t
metaOg :: Applicative m => Text -> Text -> HtmlT m ()
metaOg k v =
meta_
[ makeAttribute "property" $ "og:" <> k,
content_ v
]