rss feed and robots.txt

This commit is contained in:
Pagwin 2024-12-07 17:37:40 -05:00
parent e3cbfdb2fb
commit 11f0f80daf
No known key found for this signature in database
GPG key ID: 81137023740CA260
5 changed files with 73 additions and 14 deletions

View file

@ -4,7 +4,7 @@ outputDir :: String
outputDir = "publish" outputDir = "publish"
assetGlobs :: [String] assetGlobs :: [String]
assetGlobs = ["static//*"] assetGlobs = ["static//*", "robots.txt"]
-- CAN ONLY BE TYPST DOCS UNLESS YOU CHANGE THINGS AT THE `pages` RULE in `Main.hs -- CAN ONLY BE TYPST DOCS UNLESS YOU CHANGE THINGS AT THE `pages` RULE in `Main.hs
pagePaths :: [String] pagePaths :: [String]

View file

@ -11,12 +11,16 @@ import Config
import Control.Monad (forM, when) import Control.Monad (forM, when)
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
import Data.List (sortOn) import Data.List (sortOn)
import Data.Maybe (fromJust)
import qualified Data.Ord as Ord import qualified Data.Ord as Ord
import qualified Data.Text as T import qualified Data.Text as T
import Deriving.Aeson
import Deriving.Aeson.Stock (Vanilla)
import Development.Shake (Action, Rules, (%>), (|%>), (~>)) import Development.Shake (Action, Rules, (%>), (|%>), (~>))
import qualified Development.Shake as Shake import qualified Development.Shake as Shake
import Development.Shake.FilePath ((</>)) import Development.Shake.FilePath ((</>))
import qualified Development.Shake.FilePath as FP import qualified Development.Shake.FilePath as FP
import qualified Development.Shake.FilePath as Shake
import Templates import Templates
import Types import Types
import Utilities import Utilities
@ -79,7 +83,14 @@ pages =
let metaSrc = indexHtmlTypstMetaPath target let metaSrc = indexHtmlTypstMetaPath target
html <- typstToHtml src html <- typstToHtml src
meta <- yamlToPost metaSrc meta <- yamlToPost metaSrc
let page = Page (postTitle meta) html time <- Utilities.now
let page =
Page
{ pageTitle = postTitle meta,
pageContent = html,
pageNow = time,
pageSection = T.pack $ fromJust $ Shake.stripExtension "html" target
}
applyTemplateAndWrite "default.html" page target applyTemplateAndWrite "default.html" page target
Shake.putInfo $ "Built " <> target <> " from " <> src Shake.putInfo $ "Built " <> target <> " from " <> src
@ -111,8 +122,14 @@ typstPost src = do
post <- readTypstPost src post <- readTypstPost src
let rPost = fromPost post let rPost = fromPost post
postHtml <- applyTemplate "post.html" rPost postHtml <- applyTemplate "post.html" rPost
time <- Utilities.now
let page = Page (postTitle post) postHtml let page =
Page
{ pageTitle = rPostTitle rPost,
pageContent = postHtml,
pageNow = time,
pageSection = T.pack $ fromJust $ Shake.stripExtension "html" target
}
applyTemplateAndWrite "default.html" page target applyTemplateAndWrite "default.html" page target
Shake.putInfo $ "Built " <> target <> " from " <> src Shake.putInfo $ "Built " <> target <> " from " <> src
@ -126,7 +143,14 @@ markdownPost src = do
-- Shake.putInfo $ show . toJSON $ rPost -- Shake.putInfo $ show . toJSON $ rPost
postHtml <- applyTemplate "post.html" rPost postHtml <- applyTemplate "post.html" rPost
let page = Page (postTitle post) postHtml time <- Utilities.now
let page =
Page
{ pageTitle = rPostTitle rPost,
pageContent = postHtml,
pageNow = time,
pageSection = T.pack $ fromJust $ Shake.stripExtension "html" target
}
applyTemplateAndWrite "default.html" page target applyTemplateAndWrite "default.html" page target
Shake.putInfo $ "Built " <> target <> " from " <> src Shake.putInfo $ "Built " <> target <> " from " <> src
@ -140,7 +164,14 @@ home =
<$> forM postPaths readPost <$> forM postPaths readPost
let posts' = map fromPost posts let posts' = map fromPost posts
html <- applyTemplate "home.html" $ HM.singleton "posts" posts' html <- applyTemplate "home.html" $ HM.singleton "posts" posts'
let page = Page (T.pack "Home") html time <- Utilities.now
let page =
Page
{ pageTitle = T.pack "Home",
pageContent = html,
pageNow = time,
pageSection = T.pack $ fromJust $ Shake.stripExtension "html" target
}
applyTemplateAndWrite "default.html" page target applyTemplateAndWrite "default.html" page target
Shake.putInfo $ "Built " <> target Shake.putInfo $ "Built " <> target
@ -151,17 +182,31 @@ postList =
posts <- sortOn (Ord.Down . postDate) <$> forM postPaths readPost posts <- sortOn (Ord.Down . postDate) <$> forM postPaths readPost
let posts' = map fromPost posts let posts' = map fromPost posts
html <- applyTemplate "posts.html" $ HM.singleton "posts" posts' html <- applyTemplate "posts.html" $ HM.singleton "posts" posts'
let page = Page (T.pack "Blog Posts") html time <- Utilities.now
let page =
Page
{ pageTitle = T.pack "Blog Posts",
pageContent = html,
pageNow = time,
pageSection = T.pack $ fromJust $ Shake.stripExtension "html" target
}
applyTemplateAndWrite "default.html" page target applyTemplateAndWrite "default.html" page target
Shake.putInfo $ "Built " <> target Shake.putInfo $ "Built " <> target
data Rss = Rss
{ now :: T.Text,
posts :: [RenderedPost]
}
deriving (Show, Generic)
deriving (ToJSON) via Vanilla Rss
rss :: Rules () rss :: Rules ()
rss = rss =
outputDir </> "index.xml" %> \target -> do outputDir </> "index.xml" %> \target -> do
postPaths <- getPublishedPosts postPaths <- getPublishedPosts
posts <- sortOn (Ord.Down . postDate) <$> forM postPaths readPost posts <- map fromPost . sortOn (Ord.Down . postDate) <$> forM postPaths readPost
-- TODO: change this to actually have it's own type for things like updated time <- Utilities.now
applyTemplateAndWrite "feed.xml" (HM.singleton "posts" posts) target applyTemplateAndWrite "feed.xml" (Rss time posts) target
Shake.putInfo $ "Built " <> target Shake.putInfo $ "Built " <> target

View file

@ -10,7 +10,7 @@ import Development.Shake.FilePath ((</>))
import GHC.Stack (HasCallStack) import GHC.Stack (HasCallStack)
import qualified Text.Mustache as Mus import qualified Text.Mustache as Mus
import qualified Text.Mustache.Compile as Mus import qualified Text.Mustache.Compile as Mus
import Types (Post (postAuthor, postContent, postDate, postLink, postTags, postTitle), RenderedPost (RenderedPost, rPostAuthor, rPostContent, rPostDate, rPostHasTags, rPostIsoDate, rPostLink, rPostTags, rPostTitle)) import Types (Post (postAuthor, postContent, postDate, postDescription, postLink, postTags, postTitle), RenderedPost (RenderedPost, rPostAuthor, rPostContent, rPostDate, rPostHasTags, rPostId, rPostIsoDate, rPostLink, rPostSummary, rPostTags, rPostTitle))
import Utilities import Utilities
applyTemplate :: (HasCallStack, (ToJSON a)) => String -> a -> Action Text applyTemplate :: (HasCallStack, (ToJSON a)) => String -> a -> Action Text
@ -55,5 +55,8 @@ fromPost post =
rPostDate = postDate post, rPostDate = postDate post,
rPostIsoDate = postDate post >>= parseDate, rPostIsoDate = postDate post >>= parseDate,
rPostContent = postContent post, rPostContent = postContent post,
rPostLink = postLink post rPostLink = postLink post,
-- maybe can replace non-acceptable chars with - but unclear is exactly one - is allowed or now https://www.iana.org/assignments/urn-informal/urn-1
rPostId = T.pack . ("urn:urn-1:" ++) . filter (\c -> elem c "abcdefghijklmnopqrstuvwxyz0123456789") . T.unpack . T.toLower . postTitle $ post,
rPostSummary = postDescription post
} }

View file

@ -5,7 +5,14 @@ import Deriving.Aeson
import Deriving.Aeson.Stock (PrefixedSnake) import Deriving.Aeson.Stock (PrefixedSnake)
-- pageSection is what css class should be specified in a style html element, I would do an enum but I foresee that being a mistake -- pageSection is what css class should be specified in a style html element, I would do an enum but I foresee that being a mistake
data Page = Page {pageTitle :: Text, pageContent :: Text, pageNow :: Text, pageSection :: Text} data Page = Page
{ pageTitle :: Text,
pageContent :: Text,
-- build time
pageNow :: Text,
-- css class for page section
pageSection :: Text
}
deriving (Show, Generic) deriving (Show, Generic)
deriving (ToJSON) via PrefixedSnake "page" Page deriving (ToJSON) via PrefixedSnake "page" Page
@ -31,7 +38,7 @@ data Post = Post
postDate :: Maybe Text, postDate :: Maybe Text,
postContent :: Maybe Text, postContent :: Maybe Text,
postLink :: Maybe Text, postLink :: Maybe Text,
postSummary :: Maybe Text, postDescription :: Maybe Text,
postDraft :: Maybe Bool postDraft :: Maybe Bool
} }
deriving (Show, Generic) deriving (Show, Generic)

View file

@ -8,6 +8,7 @@ import Data.List (find)
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Data.Time import Data.Time
import Data.Time.Format.ISO8601 (iso8601Show)
import Data.Yaml.Aeson import Data.Yaml.Aeson
import Development.Shake (Action) import Development.Shake (Action)
import qualified Development.Shake as Shake import qualified Development.Shake as Shake
@ -99,6 +100,9 @@ runPandoc action =
Pandoc.runIO (Pandoc.setVerbosity Pandoc.ERROR >> action) Pandoc.runIO (Pandoc.setVerbosity Pandoc.ERROR >> action)
>>= either (fail . show) return >>= either (fail . show) return
now :: Action T.Text
now = Shake.liftIO $ fmap (T.pack . iso8601Show) getCurrentTime
markdownToPost :: FilePath -> Action Post markdownToPost :: FilePath -> Action Post
markdownToPost path = do markdownToPost path = do
content <- Shake.readFile' path content <- Shake.readFile' path