" , renderAttribution e , maybe "" renderCommentary (cpCommentary e) , renderTags (cpTags e) , "" , renderText (cpText e) , "
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE OverloadedStrings #-}
-- | Commonplace book: loads data/commonplace.yaml and renders
-- themed and chronological HTML views for /commonplace.
module Commonplace
( commonplaceCtx
) where
import Data.Aeson (FromJSON (..), withObject, (.:), (.:?), (.!=))
import Data.List (nub, sortBy)
import Data.Ord (comparing, Down (..))
import qualified Data.ByteString.Char8 as BS
import qualified Data.Yaml as Y
import Hakyll hiding (escapeHtml, renderTags)
import Contexts (siteCtx)
import Utils (escapeHtml)
-- ---------------------------------------------------------------------------
-- Entry type
-- ---------------------------------------------------------------------------
data CPEntry = CPEntry
{ cpText :: String
, cpAttribution :: String
, cpSource :: Maybe String
, cpSourceUrl :: Maybe String
, cpTags :: [String]
, cpCommentary :: Maybe String
, cpDateAdded :: String
}
instance FromJSON CPEntry where
parseJSON = withObject "CPEntry" $ \o -> CPEntry
<$> o .: "text"
<*> o .: "attribution"
<*> o .:? "source"
<*> o .:? "source-url"
<*> o .:? "tags" .!= []
<*> o .:? "commentary"
<*> o .:? "date-added" .!= ""
-- ---------------------------------------------------------------------------
-- HTML rendering
-- ---------------------------------------------------------------------------
-- | Escape HTML, then replace newlines with
for multi-line verse.
renderText :: String -> String
renderText = concatMap tr . escapeHtml . stripTrailingNL
where
tr '\n' = "
\n"
tr c = [c]
stripTrailingNL = reverse . dropWhile (== '\n') . reverse
renderAttribution :: CPEntry -> String
renderAttribution e =
"
\x2014\x202f" ++ escapeHtml (cpAttribution e) ++ maybe "" renderSource (cpSource e) ++ "
" where renderSource src = case cpSourceUrl e of Just url -> ", " ++ escapeHtml src ++ "" Nothing -> ", " ++ escapeHtml src renderTags :: [String] -> String renderTags [] = "" renderTags ts = "" renderEntry :: CPEntry -> String renderEntry e = concat [ "" , renderAttribution e , maybe "" renderCommentary (cpCommentary e) , renderTags (cpTags e) , "" , renderText (cpText e) , "
" ++ escapeHtml c ++ "
" -- --------------------------------------------------------------------------- -- Themed view -- --------------------------------------------------------------------------- -- | All distinct tags in first-occurrence order (preserves YAML ordering). allTags :: [CPEntry] -> [String] allTags = nub . concatMap cpTags renderTagSection :: String -> [CPEntry] -> String renderTagSection tag entries = concat [ "No entries yet.
" ++ "No entries yet.
" else concatMap renderEntry sorted ++ "