neuron-0.4.0.0: src/app/Data/Structured/Breadcrumb.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE NoImplicitPrelude #-}
-- | JSON for Google's structured data breadcrumbs
--
-- https://developers.google.com/search/docs/data-types/breadcrumb
module Data.Structured.Breadcrumb where
import Data.Aeson
import Data.Tree
import Lucid
import Relude
import Text.URI (URI)
import qualified Text.URI as URI
data Item = Item
{ name :: Text,
url :: Maybe URI
}
deriving (Eq, Show, Generic)
newtype Breadcrumb = Breadcrumb {unBreadcrumb :: NonEmpty Item}
deriving (Eq, Show, Generic)
instance ToHtml [Breadcrumb] where
toHtmlRaw = toHtml
toHtml bs =
script_ [type_ "application/ld+json"] $
encode bs
instance ToJSON Breadcrumb where
toJSON (Breadcrumb (toList -> crumbs)) =
toJSON $
object
[ "@context" .= toJSON context,
"@type" .= ("BreadcrumbList" :: Text),
"itemListElement" .= toJSON (uncurry itemJson <$> zip [1 :: Int ..] crumbs)
]
where
context = "https://schema.org" :: Text
itemJson pos Item {..} =
object
[ "@type" .= toJSON ("ListItem" :: Text),
"position" .= toJSON pos,
"name" .= toJSON name,
"item" .= toJSON (fmap URI.render url)
]
fromForest :: Forest Item -> [Breadcrumb]
fromForest =
fmap Breadcrumb . mapMaybe (nonEmpty . reverse) . concatMap (foldTree f)
where
f :: Item -> [[[Item]]] -> [[Item]]
f parent = \case
[] -> [[parent]]
childPaths ->
fmap (parent :) `concatMap` childPaths
{-
[{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Books",
"item": "https://example.com/books"
},{
"@type": "ListItem",
"position": 2,
"name": "Science Fiction",
"item": "https://example.com/books/sciencefiction"
},{
"@type": "ListItem",
"position": 3,
"name": "Award Winners"
}]
},
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Literature",
"item": "https://example.com/literature"
},{
"@type": "ListItem",
"position": 2,
"name": "Award Winners"
}]
}]
-}