{-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} -- | Meta tags for The Open Graph protocol: https://ogp.me/ 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 -- The OpenGraph metadata -- -- This type can be directly rendered to HTML using `toHTML`. 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 -- TODO: Remaining ADT values & sub-fields 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" -- TODO: _article_profile :: [Profile] 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 -- Open graph meta element metaOg :: Applicative m => Text -> Text -> HtmlT m () metaOg k v = meta_ [ makeAttribute "property" $ "og:" <> k, content_ v ]