Directly store each Markdown content's path in the data structure to save having to re-build the same concatenation again and again for all the various outputs where the path matters ; also handles elegantly the «issue» of pagesPath being a Maybe FilePath because pages are optional
This commit is contained in:
parent
ce3003178f
commit
19b3694d06
6 changed files with 27 additions and 23 deletions
|
@ -36,7 +36,7 @@ instance ToJSON Skin where
|
||||||
findImage :: String -> Maybe FilePath -> IO (Maybe FilePath)
|
findImage :: String -> Maybe FilePath -> IO (Maybe FilePath)
|
||||||
findImage _ (Just path) = return . Just $ absoluteLink path
|
findImage _ (Just path) = return . Just $ absoluteLink path
|
||||||
findImage name Nothing =
|
findImage name Nothing =
|
||||||
fmap absoluteLink . listToMaybe <$> filterM doesFileExist pathsToCheck
|
listToMaybe <$> filterM doesFileExist pathsToCheck
|
||||||
where
|
where
|
||||||
directories = [".", "image", "images", "pictures", "skin", "static"]
|
directories = [".", "image", "images", "pictures", "skin", "static"]
|
||||||
extensions = ["ico", "gif", "jpeg", "jpg", "png", "svg"]
|
extensions = ["ico", "gif", "jpeg", "jpg", "png", "svg"]
|
||||||
|
|
12
src/DOM.hs
12
src/DOM.hs
|
@ -9,7 +9,7 @@ import qualified Article (preview)
|
||||||
import ArticlesList (
|
import ArticlesList (
|
||||||
ArticlesList(..), description, getArticles, otherURL, rssLinkTexts
|
ArticlesList(..), description, getArticles, otherURL, rssLinkTexts
|
||||||
)
|
)
|
||||||
import Blog (Blog(..), Path(..), Skin(..), URL(..), template)
|
import Blog (Blog(..), Skin(..), URL(..), template)
|
||||||
import Control.Monad.Reader (ReaderT, asks)
|
import Control.Monad.Reader (ReaderT, asks)
|
||||||
import qualified Data.Map as Map (keys)
|
import qualified Data.Map as Map (keys)
|
||||||
import Data.Text (pack, empty)
|
import Data.Text (pack, empty)
|
||||||
|
@ -24,7 +24,7 @@ import Lucid (
|
||||||
import Markdown (Markdown(..))
|
import Markdown (Markdown(..))
|
||||||
import Prelude hiding (head, lookup)
|
import Prelude hiding (head, lookup)
|
||||||
import Pretty ((.$))
|
import Pretty ((.$))
|
||||||
import System.FilePath.Posix ((</>), (<.>))
|
import System.FilePath.Posix ((<.>))
|
||||||
|
|
||||||
type HtmlGenerator = HtmlT (ReaderT Blog IO)
|
type HtmlGenerator = HtmlT (ReaderT Blog IO)
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ instance HasContent ArticlesList where
|
||||||
rssLink False = return ()
|
rssLink False = return ()
|
||||||
|
|
||||||
markdown :: Bool -> Markdown -> HtmlGenerator ()
|
markdown :: Bool -> Markdown -> HtmlGenerator ()
|
||||||
markdown raw (Markdown {key, body, title}) = do
|
markdown raw (Markdown {key, Markdown.path, body, title}) =
|
||||||
url <- absoluteLink . (</> key <.> extension) <$> (asks $path.$articlesPath)
|
let url = absoluteLink $ path <.> extension in
|
||||||
article_ [id_ $ pack key] (do
|
article_ [id_ $ pack key] (do
|
||||||
header_ (do
|
header_ (do
|
||||||
a_ [href_ $ pack url] . h1_ $ toHtml title
|
a_ [href_ $ pack url] . h1_ $ toHtml title
|
||||||
|
@ -78,7 +78,9 @@ defaultBanner = do
|
||||||
)
|
)
|
||||||
|
|
||||||
faviconLink :: FilePath -> HtmlGenerator ()
|
faviconLink :: FilePath -> HtmlGenerator ()
|
||||||
faviconLink url = link_ [rel_ "shortcut icon", href_ $ pack url, type_ "image/x-icon"]
|
faviconLink url = link_ [
|
||||||
|
rel_ "shortcut icon", href_ . pack $ absoluteLink url, type_ "image/x-icon"
|
||||||
|
]
|
||||||
|
|
||||||
optional :: (a -> HtmlGenerator ()) -> Maybe a -> HtmlGenerator ()
|
optional :: (a -> HtmlGenerator ()) -> Maybe a -> HtmlGenerator ()
|
||||||
optional = maybe (return ())
|
optional = maybe (return ())
|
||||||
|
|
|
@ -21,6 +21,7 @@ import Lucid.Base (makeAttribute)
|
||||||
import qualified Markdown (Markdown(..))
|
import qualified Markdown (Markdown(..))
|
||||||
import Page (Page(..))
|
import Page (Page(..))
|
||||||
import Pretty ((.$))
|
import Pretty ((.$))
|
||||||
|
import System.FilePath.Posix ((</>), (<.>))
|
||||||
|
|
||||||
class HasCard a where
|
class HasCard a where
|
||||||
cardType :: Renderer m => a -> m Text
|
cardType :: Renderer m => a -> m Text
|
||||||
|
@ -46,7 +47,7 @@ make element siteURL = do
|
||||||
og "site_name" =<< (asks $name.$pack)
|
og "site_name" =<< (asks $name.$pack)
|
||||||
where
|
where
|
||||||
maybeImage = maybe (return ()) (og "image" . sitePrefix)
|
maybeImage = maybe (return ()) (og "image" . sitePrefix)
|
||||||
sitePrefix = pack . (siteURL ++)
|
sitePrefix = pack . (siteURL </>)
|
||||||
|
|
||||||
instance HasCard Article where
|
instance HasCard Article where
|
||||||
cardType _ = return "article"
|
cardType _ = return "article"
|
||||||
|
@ -57,7 +58,7 @@ instance HasCard Article where
|
||||||
image (Article (Markdown.Markdown {Markdown.metadata})) =
|
image (Article (Markdown.Markdown {Markdown.metadata})) =
|
||||||
return $ Map.lookup "featuredImage" metadata
|
return $ Map.lookup "featuredImage" metadata
|
||||||
title = return . Markdown.title . Article.getMarkdown
|
title = return . Markdown.title . Article.getMarkdown
|
||||||
urlPath = fmap (\t -> "/articles/" ++ t ++ ".html") . title
|
urlPath (Article markdown) = return $ Markdown.path markdown <.> "html"
|
||||||
|
|
||||||
instance HasCard Page where
|
instance HasCard Page where
|
||||||
cardType _ = return "website"
|
cardType _ = return "website"
|
||||||
|
@ -68,7 +69,7 @@ instance HasCard Page where
|
||||||
image (Page (Markdown.Markdown {Markdown.metadata})) =
|
image (Page (Markdown.Markdown {Markdown.metadata})) =
|
||||||
return $ Map.lookup "featuredImage" metadata
|
return $ Map.lookup "featuredImage" metadata
|
||||||
title = return . Markdown.title . Page.getMarkdown
|
title = return . Markdown.title . Page.getMarkdown
|
||||||
urlPath = fmap (\t -> "/pages/" ++ t ++ ".html") . title
|
urlPath (Page markdown) = return $ Markdown.path markdown <.> "html"
|
||||||
|
|
||||||
instance HasCard ArticlesList where
|
instance HasCard ArticlesList where
|
||||||
cardType _ = return "website"
|
cardType _ = return "website"
|
||||||
|
@ -76,6 +77,6 @@ instance HasCard ArticlesList where
|
||||||
image _ = return Nothing
|
image _ = return Nothing
|
||||||
title (ArticlesList {collection}) = Collection.title collection
|
title (ArticlesList {collection}) = Collection.title collection
|
||||||
urlPath al@(ArticlesList {collection}) =
|
urlPath al@(ArticlesList {collection}) =
|
||||||
return $ maybe "" ('/':) (tag collection) ++ file
|
return $ maybe "" id (tag collection) </> file
|
||||||
where
|
where
|
||||||
file = '/' : (if full al then "all" else "index") ++ ".html"
|
file = (if full al then "all" else "index") <.> ".html"
|
||||||
|
|
|
@ -29,8 +29,8 @@ articlesLists collection@(Collection {basePath}) = [
|
||||||
|
|
||||||
generateArticles :: [Article] -> ReaderT Blog IO ()
|
generateArticles :: [Article] -> ReaderT Blog IO ()
|
||||||
generateArticles = mapM_ $ \article -> do
|
generateArticles = mapM_ $ \article -> do
|
||||||
baseDir <- (</>) <$> (asks $path.$root) <*> (asks $path.$articlesPath)
|
let relativePath = Markdown.path (Article.getMarkdown article) <.> "html"
|
||||||
let filePath = baseDir </> key (Article.getMarkdown article) <.> "html"
|
filePath <- (</> relativePath) <$> (asks $Blog.path.$root)
|
||||||
(renderTextT $ htmlDocument article) >>= liftIO . TextIO.writeFile filePath
|
(renderTextT $ htmlDocument article) >>= liftIO . TextIO.writeFile filePath
|
||||||
|
|
||||||
generateCollection :: Collection -> ReaderT Blog IO ()
|
generateCollection :: Collection -> ReaderT Blog IO ()
|
||||||
|
|
|
@ -4,7 +4,6 @@ module Markdown (
|
||||||
, Metadata
|
, Metadata
|
||||||
, at
|
, at
|
||||||
, getKey
|
, getKey
|
||||||
, parser
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Applicative ((<|>))
|
import Control.Applicative ((<|>))
|
||||||
|
@ -15,24 +14,27 @@ import Text.ParserCombinators.Parsec (
|
||||||
ParseError, Parser
|
ParseError, Parser
|
||||||
, (<?>)
|
, (<?>)
|
||||||
, anyChar, char, count, endBy, eof, getPosition, many, many1, noneOf
|
, anyChar, char, count, endBy, eof, getPosition, many, many1, noneOf
|
||||||
, oneOf, option, parse, skipMany, sourceLine, string, try
|
, oneOf, option, parse, skipMany, sourceLine, sourceName, string, try
|
||||||
)
|
)
|
||||||
|
|
||||||
type Metadata = Map String String
|
type Metadata = Map String String
|
||||||
data Markdown = Markdown {
|
data Markdown = Markdown {
|
||||||
key :: String
|
key :: String
|
||||||
|
, path :: String
|
||||||
, title :: String
|
, title :: String
|
||||||
, metadata :: Metadata
|
, metadata :: Metadata
|
||||||
, bodyOffset :: Int
|
, bodyOffset :: Int
|
||||||
, body :: [String]
|
, body :: [String]
|
||||||
}
|
}
|
||||||
|
|
||||||
parser :: String -> Parser Markdown
|
parser :: Parser Markdown
|
||||||
parser key = do
|
parser = do
|
||||||
(title, metadata) <- skipMany eol *> (headerP <|> reverseHeaderP)
|
(title, metadata) <- skipMany eol *> (headerP <|> reverseHeaderP)
|
||||||
bodyOffset <- skipMany eol *> (pred . sourceLine <$> getPosition)
|
bodyOffset <- skipMany eol *> (pred . sourceLine <$> getPosition)
|
||||||
body <- lines <$> many anyChar <* eof
|
body <- lines <$> many anyChar <* eof
|
||||||
return $ Markdown {key, title, metadata, bodyOffset, body}
|
inputFile <- sourceName <$> getPosition
|
||||||
|
let (key, path) = (getKey inputFile, dropExtension inputFile)
|
||||||
|
return $ Markdown {key, path, title, metadata, bodyOffset, body}
|
||||||
where
|
where
|
||||||
headerP = (,) <$> titleP <* many eol <*> metadataP
|
headerP = (,) <$> titleP <* many eol <*> metadataP
|
||||||
reverseHeaderP = flip (,) <$> metadataP <* many eol<*> titleP
|
reverseHeaderP = flip (,) <$> metadataP <* many eol<*> titleP
|
||||||
|
@ -67,4 +69,4 @@ getKey :: FilePath -> String
|
||||||
getKey = dropExtension . takeFileName
|
getKey = dropExtension . takeFileName
|
||||||
|
|
||||||
at :: FilePath -> IO (Either ParseError Markdown)
|
at :: FilePath -> IO (Either ParseError Markdown)
|
||||||
at filePath = parse (parser (getKey filePath)) filePath <$> readFile filePath
|
at filePath = parse parser filePath <$> readFile filePath
|
||||||
|
|
|
@ -8,7 +8,7 @@ module RSS (
|
||||||
import Article (Article(..))
|
import Article (Article(..))
|
||||||
import ArticlesList (ArticlesList(..), getArticles)
|
import ArticlesList (ArticlesList(..), getArticles)
|
||||||
import qualified ArticlesList (description)
|
import qualified ArticlesList (description)
|
||||||
import Blog (Blog(..), Path(..), Renderer, URL(..))
|
import Blog (Blog(urls), Renderer, URL(..))
|
||||||
import Collection (Collection(..), getAll)
|
import Collection (Collection(..), getAll)
|
||||||
import qualified Collection (title)
|
import qualified Collection (title)
|
||||||
import Control.Monad.IO.Class (MonadIO(..))
|
import Control.Monad.IO.Class (MonadIO(..))
|
||||||
|
@ -58,13 +58,12 @@ pubDate_ :: Term arg result => arg -> result
|
||||||
pubDate_ = term "pubDate"
|
pubDate_ = term "pubDate"
|
||||||
|
|
||||||
articleItem :: MonadReader Blog m => String -> Article -> HtmlT m ()
|
articleItem :: MonadReader Blog m => String -> Article -> HtmlT m ()
|
||||||
articleItem siteURL (Article (Markdown {key, metadata, title})) =
|
articleItem siteURL (Article (Markdown {path, metadata, title})) =
|
||||||
item_ $ do
|
item_ $ do
|
||||||
title_ $ toHtml title
|
title_ $ toHtml title
|
||||||
link_ . toHtml =<< link <$> (asks $path.$articlesPath)
|
link_ $ toHtml (siteURL </> path <.> "html")
|
||||||
pubDate_ . toHtml . rfc822Date $ metadata ! "date"
|
pubDate_ . toHtml . rfc822Date $ metadata ! "date"
|
||||||
where
|
where
|
||||||
link path = siteURL </> path </> key <.> "html"
|
|
||||||
rfc822Date =
|
rfc822Date =
|
||||||
formatTime defaultTimeLocale rfc822DateFormat
|
formatTime defaultTimeLocale rfc822DateFormat
|
||||||
. posixSecondsToUTCTime . fromIntegral . (read :: String -> Int)
|
. posixSecondsToUTCTime . fromIntegral . (read :: String -> Int)
|
||||||
|
|
Loading…
Reference in a new issue