Implement customizable texts
This commit is contained in:
parent
00c3c602b9
commit
339a1e0d20
9 changed files with 176 additions and 33 deletions
|
@ -18,6 +18,7 @@ extra-source-files: CHANGELOG.md
|
||||||
build-type: Simple
|
build-type: Simple
|
||||||
data-dir: share
|
data-dir: share
|
||||||
data-files: js/*.js
|
data-files: js/*.js
|
||||||
|
defaultWording.conf
|
||||||
|
|
||||||
executable hablo
|
executable hablo
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
|
@ -27,6 +28,7 @@ executable hablo
|
||||||
, Blog
|
, Blog
|
||||||
, Blog.Path
|
, Blog.Path
|
||||||
, Blog.Skin
|
, Blog.Skin
|
||||||
|
, Blog.Wording
|
||||||
, Dom
|
, Dom
|
||||||
, Files
|
, Files
|
||||||
, HTML
|
, HTML
|
||||||
|
@ -45,6 +47,7 @@ executable hablo
|
||||||
, mtl
|
, mtl
|
||||||
, optparse-applicative
|
, optparse-applicative
|
||||||
, parsec
|
, parsec
|
||||||
|
, template
|
||||||
, text
|
, text
|
||||||
, time
|
, time
|
||||||
, unix
|
, unix
|
||||||
|
|
7
share/defaultWording.conf
Normal file
7
share/defaultWording.conf
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
allLink = See all
|
||||||
|
allPage = All articles
|
||||||
|
allTaggedPage = All articles tagged ${tag}
|
||||||
|
latestLink = See only latest
|
||||||
|
latestPage = Latest articles
|
||||||
|
latestTaggedPage = Latest articles tagged ${tag}
|
||||||
|
tagsList = Tags
|
|
@ -64,7 +64,12 @@ function DomRenderer(modules) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function pageTitle(tag, all) {
|
function pageTitle(tag, all) {
|
||||||
return (all ? 'All' : 'Latest') + ' articles' + (tag != undefined ? ' tagged ' + tag : '');
|
if(tag != undefined) {
|
||||||
|
var template = blog.wording[all ? 'allTaggedPage' : 'latestTaggedPage'];
|
||||||
|
return template.replace(/([^$]|^)\$(?:{tag}|tag([^a-zA-Z]|$))/, '$1' + tag + '$2');
|
||||||
|
} else {
|
||||||
|
return blog.wording[all ? 'allPage' : 'latestPage'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function otherUrl(tag, all) {
|
function otherUrl(tag, all) {
|
||||||
|
@ -78,7 +83,7 @@ function DomRenderer(modules) {
|
||||||
modules.dom.make('h2', {innerText: pageTitle(tag, all)}),
|
modules.dom.make('h2', {innerText: pageTitle(tag, all)}),
|
||||||
modules.dom.make('a', {
|
modules.dom.make('a', {
|
||||||
class: 'navigation',
|
class: 'navigation',
|
||||||
innerText: all ? 'See only latest' : 'See all',
|
innerText: all ? blog.wording.latestLink : blog.wording.allLink,
|
||||||
href: otherUrl(tag, all)
|
href: otherUrl(tag, all)
|
||||||
}),
|
}),
|
||||||
modules.dom.make('div', {class: 'articles'}, articlePreviews.filter(modules.fun.defined))
|
modules.dom.make('div', {class: 'articles'}, articlePreviews.filter(modules.fun.defined))
|
||||||
|
|
|
@ -25,6 +25,7 @@ data Arguments = BlogConfig {
|
||||||
, pagesPath :: Maybe FilePath
|
, pagesPath :: Maybe FilePath
|
||||||
, previewArticlesCount :: Int
|
, previewArticlesCount :: Int
|
||||||
, previewLinesCount :: Int
|
, previewLinesCount :: Int
|
||||||
|
, wording :: Maybe FilePath
|
||||||
}
|
}
|
||||||
| Version
|
| Version
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ blogConfig = BlogConfig
|
||||||
<> long "preview-lines"
|
<> long "preview-lines"
|
||||||
<> help "number of lines to display in articles preview"
|
<> help "number of lines to display in articles preview"
|
||||||
)
|
)
|
||||||
|
<*> option filePath 'w' "wording" "WORDING" "path to the file containing the wording to use"
|
||||||
|
|
||||||
version :: Parser Arguments
|
version :: Parser Arguments
|
||||||
version = flag' Version (
|
version = flag' Version (
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
{-# LANGUAGE NamedFieldPuns #-}
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
module ArticlesList (
|
module ArticlesList (
|
||||||
ArticlesList(..)
|
ArticlesList(..)
|
||||||
, otherLink
|
|
||||||
, otherUrl
|
, otherUrl
|
||||||
, pageTitle
|
, pageTitle
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Article (Article)
|
import Article (Article)
|
||||||
|
import Blog (Blog(..), Wording(..), get)
|
||||||
|
import Control.Monad.Reader (MonadReader)
|
||||||
|
import Data.Text (Text, pack)
|
||||||
|
import Data.Text.Lazy (toStrict)
|
||||||
|
import Data.Text.Template (render)
|
||||||
|
import Pretty ((.$))
|
||||||
import System.FilePath.Posix ((</>))
|
import System.FilePath.Posix ((</>))
|
||||||
|
|
||||||
data ArticlesList = ArticlesList {
|
data ArticlesList = ArticlesList {
|
||||||
|
@ -23,12 +30,11 @@ otherUrl (ArticlesList {full, tagged}) =
|
||||||
where
|
where
|
||||||
url = maybe "/" ("/" </>)
|
url = maybe "/" ("/" </>)
|
||||||
|
|
||||||
otherLink :: ArticlesList -> String
|
pageTitle :: (MonadReader Blog m) => ArticlesList -> m Text
|
||||||
otherLink (ArticlesList {full}) =
|
pageTitle (ArticlesList {full, tagged}) = do
|
||||||
if full
|
template <- Blog.get $wording.$(if full then allTaggedPage else latestTaggedPage)
|
||||||
then "See only latest"
|
untagged <- Blog.get $wording.$(if full then allPage else latestPage)
|
||||||
else "See all"
|
return $ maybe untagged (toStrict . render template . tag) tagged
|
||||||
|
where
|
||||||
pageTitle :: ArticlesList -> String
|
tag :: String -> Text -> Text
|
||||||
pageTitle (ArticlesList {full, tagged}) =
|
tag t = \"tag" -> pack t
|
||||||
(if full then "All" else "Latest") ++ " articles" ++ maybe "" (" tagged " ++) tagged
|
|
||||||
|
|
13
src/Blog.hs
13
src/Blog.hs
|
@ -4,6 +4,7 @@ module Blog (
|
||||||
Blog(..)
|
Blog(..)
|
||||||
, Path(..)
|
, Path(..)
|
||||||
, Skin(..)
|
, Skin(..)
|
||||||
|
, Wording(..)
|
||||||
, build
|
, build
|
||||||
, get
|
, get
|
||||||
) where
|
) where
|
||||||
|
@ -16,11 +17,13 @@ import Blog.Path (Path(..))
|
||||||
import qualified Blog.Path as Path (build)
|
import qualified Blog.Path as Path (build)
|
||||||
import Blog.Skin (Skin(..))
|
import Blog.Skin (Skin(..))
|
||||||
import qualified Blog.Skin as Skin (build)
|
import qualified Blog.Skin as Skin (build)
|
||||||
|
import Blog.Wording (Wording(..))
|
||||||
|
import qualified Blog.Wording as Wording (build)
|
||||||
import Control.Monad ((>=>), filterM, forM)
|
import Control.Monad ((>=>), filterM, forM)
|
||||||
import Control.Monad.Reader (MonadReader, ask)
|
import Control.Monad.Reader (MonadReader, ask)
|
||||||
import Data.Either (rights)
|
import Data.Either (rights)
|
||||||
import Data.Map (Map)
|
import Data.Map (Map, (!?))
|
||||||
import qualified Data.Map as Map (fromList, member)
|
import qualified Data.Map as Map (fromList)
|
||||||
import Data.Set (Set)
|
import Data.Set (Set)
|
||||||
import qualified Data.Set as Set (empty, null, singleton, union)
|
import qualified Data.Set as Set (empty, null, singleton, union)
|
||||||
import qualified Files (find)
|
import qualified Files (find)
|
||||||
|
@ -35,6 +38,7 @@ data Blog = Blog {
|
||||||
, path :: Path
|
, path :: Path
|
||||||
, skin :: Skin
|
, skin :: Skin
|
||||||
, tags :: Map String (Set String)
|
, tags :: Map String (Set String)
|
||||||
|
, wording :: Wording
|
||||||
}
|
}
|
||||||
|
|
||||||
get :: MonadReader Blog m => (Blog -> a) -> m a
|
get :: MonadReader Blog m => (Blog -> a) -> m a
|
||||||
|
@ -58,17 +62,18 @@ tagged collection path = do
|
||||||
fileExists <- doesFileExist link
|
fileExists <- doesFileExist link
|
||||||
return $ if fileExists
|
return $ if fileExists
|
||||||
then let articleKey = Article.getKey link in
|
then let articleKey = Article.getKey link in
|
||||||
if Map.member articleKey collection then Set.singleton articleKey else Set.empty
|
maybe Set.empty (\_ -> Set.singleton articleKey) (collection !? articleKey)
|
||||||
else Set.empty
|
else Set.empty
|
||||||
return (takeFileName path, foldl Set.union Set.empty keys)
|
return (takeFileName path, foldl Set.union Set.empty keys)
|
||||||
|
|
||||||
build :: Arguments -> IO Blog
|
build :: Arguments -> IO Blog
|
||||||
build arguments = withCurrentDirectory (root path) $ do
|
build arguments = withCurrentDirectory (root path) $ do
|
||||||
skin <- Skin.build name arguments
|
skin <- Skin.build name arguments
|
||||||
|
wording <- Wording.build arguments
|
||||||
articles <- findArticles $ articlesPath path
|
articles <- findArticles $ articlesPath path
|
||||||
tags <- Map.fromList . filter (not . Set.null . snd)
|
tags <- Map.fromList . filter (not . Set.null . snd)
|
||||||
<$> (Files.find (articlesPath path </> "tags") >>= mapM (articles `tagged`))
|
<$> (Files.find (articlesPath path </> "tags") >>= mapM (articles `tagged`))
|
||||||
return $ Blog {articles, name, path, skin, tags}
|
return $ Blog {articles, name, path, skin, tags, wording}
|
||||||
where
|
where
|
||||||
path = Path.build arguments
|
path = Path.build arguments
|
||||||
name = maybe (takeFileName . dropTrailingPathSeparator $ root path) id
|
name = maybe (takeFileName . dropTrailingPathSeparator $ root path) id
|
||||||
|
|
89
src/Blog/Wording.hs
Normal file
89
src/Blog/Wording.hs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
module Blog.Wording (
|
||||||
|
Wording(..)
|
||||||
|
, build
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Arguments (Arguments(..))
|
||||||
|
import Control.Monad (foldM)
|
||||||
|
import Data.List (intercalate)
|
||||||
|
import Data.Map (Map, (!))
|
||||||
|
import qualified Data.Map as Map (empty, fromList, map, union)
|
||||||
|
import Data.Text (Text)
|
||||||
|
import qualified Data.Text as Text (pack, unpack)
|
||||||
|
import Data.Text.Template (Template, renderA, templateSafe)
|
||||||
|
import Paths_hablo (getDataFileName)
|
||||||
|
import Text.ParserCombinators.Parsec (
|
||||||
|
Parser
|
||||||
|
, (<|>)
|
||||||
|
, char, choice, endBy, many, many1, noneOf, parse, string, try
|
||||||
|
)
|
||||||
|
import System.Exit (die)
|
||||||
|
|
||||||
|
data Wording = Wording {
|
||||||
|
allLink :: Text
|
||||||
|
, allPage :: Text
|
||||||
|
, allTaggedPage :: Template
|
||||||
|
, latestLink :: Text
|
||||||
|
, latestPage :: Text
|
||||||
|
, latestTaggedPage :: Template
|
||||||
|
, tagsList :: Text
|
||||||
|
}
|
||||||
|
|
||||||
|
keys :: [Parser String]
|
||||||
|
keys = try . string <$> [
|
||||||
|
"allLink"
|
||||||
|
, "allPage"
|
||||||
|
, "allTaggedPage"
|
||||||
|
, "latestLink"
|
||||||
|
, "latestPage"
|
||||||
|
, "latestTaggedPage"
|
||||||
|
, "tagsList"
|
||||||
|
]
|
||||||
|
|
||||||
|
addWording :: Map String Text -> FilePath -> IO (Map String Text)
|
||||||
|
addWording currentWording wordingFile = do
|
||||||
|
parsed <- parse wordingP wordingFile <$> readFile wordingFile
|
||||||
|
case parsed of
|
||||||
|
Left errorMessage -> die $ show errorMessage
|
||||||
|
Right newWording -> return $ Map.union currentWording newWording
|
||||||
|
|
||||||
|
wordingP :: Parser (Map String Text)
|
||||||
|
wordingP = Map.map Text.pack . Map.fromList <$> (many eol *> line `endBy` (many1 eol))
|
||||||
|
where
|
||||||
|
line = (,) <$> (choice keys <* equal) <*> many (noneOf "\r\n")
|
||||||
|
equal = many (char ' ') *> char '=' *> many (char ' ')
|
||||||
|
eol = try (string "\r\n") <|> string "\r" <|> string "\n"
|
||||||
|
|
||||||
|
checkTemplateWith :: [Text] -> String -> Map String Text -> IO Template
|
||||||
|
checkTemplateWith variables key wording =
|
||||||
|
let templateText = wording ! key in
|
||||||
|
let testEnvironment = flip lookup [(s, "") | s <- variables] in
|
||||||
|
case templateSafe templateText of
|
||||||
|
Left (row, col) -> die $ syntaxError (show row) (show col)
|
||||||
|
Right template ->
|
||||||
|
maybe (die badTemplate) (return . const template) (renderA template testEnvironment)
|
||||||
|
where
|
||||||
|
availableVariables =
|
||||||
|
" (available variables: " ++ intercalate ", " (Text.unpack <$> variables) ++ ")"
|
||||||
|
syntaxError row col =
|
||||||
|
"Syntax error in template for variable " ++ key ++ "at l." ++ row ++ ", c." ++ col
|
||||||
|
badTemplate = "Invalid template for variable " ++ key ++ availableVariables
|
||||||
|
|
||||||
|
build :: Arguments -> IO Wording
|
||||||
|
build arguments = do
|
||||||
|
defaultWording <- getDataFileName "defaultWording.conf"
|
||||||
|
let wordingFiles = maybe id (:) (wording arguments) $ [defaultWording]
|
||||||
|
wording <- foldM addWording Map.empty wordingFiles
|
||||||
|
allTaggedPage <- checkTemplateWith ["tag"] "allTaggedPage" wording
|
||||||
|
latestTaggedPage <- checkTemplateWith ["tag"] "latestTaggedPage" wording
|
||||||
|
return Wording {
|
||||||
|
allLink = wording ! "allLink"
|
||||||
|
, allPage = wording ! "allPage"
|
||||||
|
, allTaggedPage
|
||||||
|
, latestLink = wording ! "latestLink"
|
||||||
|
, latestPage = wording ! "latestPage"
|
||||||
|
, latestTaggedPage
|
||||||
|
, tagsList = wording ! "tagsList"
|
||||||
|
}
|
33
src/Dom.hs
33
src/Dom.hs
|
@ -6,13 +6,13 @@ module Dom (
|
||||||
|
|
||||||
import Article (Article(..))
|
import Article (Article(..))
|
||||||
import qualified Article (preview)
|
import qualified Article (preview)
|
||||||
import ArticlesList (ArticlesList(..), otherLink, otherUrl, pageTitle)
|
import ArticlesList (ArticlesList(..), otherUrl, pageTitle)
|
||||||
import Blog (Blog(..), Path(..), Skin(..))
|
import Blog (Blog(..), Path(..), Skin(..), Wording(..))
|
||||||
import qualified Blog (get)
|
import qualified Blog (get)
|
||||||
import Control.Monad.Reader (ReaderT)
|
import Control.Monad.Reader (ReaderT)
|
||||||
import qualified Data.Map as Map (keys)
|
import qualified Data.Map as Map (keys)
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Data.Text (pack, empty)
|
import Data.Text (Text, pack, empty)
|
||||||
import Lucid
|
import Lucid
|
||||||
import Lucid.Base (makeAttribute)
|
import Lucid.Base (makeAttribute)
|
||||||
import Prelude hiding (head)
|
import Prelude hiding (head)
|
||||||
|
@ -27,23 +27,24 @@ class Page a where
|
||||||
|
|
||||||
instance Page Article where
|
instance Page Article where
|
||||||
card (Article {title}) =
|
card (Article {title}) =
|
||||||
("A new article on " <>) <$> Blog.get name
|
makeCard title =<< (Blog.get $name.$("A new article on " <>).$pack)
|
||||||
>>= makeCard title
|
|
||||||
|
|
||||||
content = article True
|
content = article True
|
||||||
|
|
||||||
instance Page ArticlesList where
|
instance Page ArticlesList where
|
||||||
card al = do
|
card al = do
|
||||||
blogName <- Blog.get name
|
blogName <- Blog.get name
|
||||||
makeCard (maybe blogName ((blogName ++ " - ") ++) $ tagged al) (pageTitle al)
|
makeCard (maybe blogName ((blogName ++ " - ") ++) $ tagged al) =<< pageTitle al
|
||||||
|
|
||||||
content al@(ArticlesList {featured}) = do
|
content al@(ArticlesList {featured, full}) = do
|
||||||
preview <- Article.preview <$> (Blog.get $skin.$previewLinesCount)
|
preview <- Article.preview <$> (Blog.get $skin.$previewLinesCount)
|
||||||
h2_ . toHtml . pack $ pageTitle al
|
h2_ . toHtml =<< pageTitle al
|
||||||
navigationA [href_ . pack $ otherUrl al] . toHtml . pack $ otherLink al
|
navigationA [href_ . pack $ otherUrl al] . toHtml =<< otherLink
|
||||||
div_ [class_ "articles"] (
|
div_ [class_ "articles"] (
|
||||||
mapM_ (article False . preview) featured
|
mapM_ (article False . preview) featured
|
||||||
)
|
)
|
||||||
|
where
|
||||||
|
otherLink = Blog.get $wording.$(if full then latestLink else allLink)
|
||||||
|
|
||||||
article :: Bool -> Article -> HtmlGenerator ()
|
article :: Bool -> Article -> HtmlGenerator ()
|
||||||
article raw (Article {key, body, title}) = do
|
article raw (Article {key, body, title}) = do
|
||||||
|
@ -57,14 +58,14 @@ article raw (Article {key, body, title}) = do
|
||||||
where
|
where
|
||||||
(aElem, extension) = if raw then (a_, "md") else (navigationA, "html")
|
(aElem, extension) = if raw then (a_, "md") else (navigationA, "html")
|
||||||
|
|
||||||
makeCard :: String -> String -> HtmlGenerator ()
|
makeCard :: String -> Text -> HtmlGenerator ()
|
||||||
makeCard title description = do
|
makeCard title description = do
|
||||||
og "title" title
|
og "title" $ pack title
|
||||||
og "description" description
|
og "description" description
|
||||||
og "image" =<< (Blog.get $skin.$cardImage)
|
og "image" =<< (Blog.get $skin.$cardImage.$pack)
|
||||||
og "site_name" =<< Blog.get name
|
og "site_name" =<< (Blog.get $name.$pack)
|
||||||
where
|
where
|
||||||
og attribute value = meta_ [makeAttribute "property" $ "og:" <> attribute , content_ $ pack value]
|
og attribute value = meta_ [makeAttribute "property" $ "og:" <> attribute , content_ value]
|
||||||
|
|
||||||
navigationA :: Term arg result => arg -> result
|
navigationA :: Term arg result => arg -> result
|
||||||
navigationA = "a" `termWith` [class_ "navigation"]
|
navigationA = "a" `termWith` [class_ "navigation"]
|
||||||
|
@ -97,9 +98,9 @@ page aPage =
|
||||||
(Blog.get $skin.$head) >>= maybe (toHtml empty) toHtmlRaw
|
(Blog.get $skin.$head) >>= maybe (toHtml empty) toHtmlRaw
|
||||||
)
|
)
|
||||||
body_ (do
|
body_ (do
|
||||||
(Blog.get $skin.$banner) >>= maybe defaultBanner toHtmlRaw
|
maybe defaultBanner toHtmlRaw =<< (Blog.get $skin.$banner)
|
||||||
div_ [id_ "navigator"] (do
|
div_ [id_ "navigator"] (do
|
||||||
h2_ "Tags"
|
h2_ =<< (Blog.get $wording.$tagsList.$toHtml)
|
||||||
ul_ . mapM_ tag . Map.keys =<< Blog.get tags
|
ul_ . mapM_ tag . Map.keys =<< Blog.get tags
|
||||||
)
|
)
|
||||||
div_ [id_ "contents"] $ content aPage
|
div_ [id_ "contents"] $ content aPage
|
||||||
|
|
27
src/JSON.hs
27
src/JSON.hs
|
@ -7,13 +7,15 @@ module JSON (
|
||||||
import Article (Article)
|
import Article (Article)
|
||||||
import qualified Article (Article(..))
|
import qualified Article (Article(..))
|
||||||
import Blog (Blog)
|
import Blog (Blog)
|
||||||
import qualified Blog (Blog(..), Path(..), Skin(..))
|
import qualified Blog (Blog(..), Path(..), Skin(..), Wording(..))
|
||||||
import Control.Monad.Reader (ReaderT, ask)
|
import Control.Monad.Reader (ReaderT, ask)
|
||||||
import Data.Aeson (ToJSON(..), genericToEncoding, defaultOptions, encode)
|
import Data.Aeson (ToJSON(..), genericToEncoding, defaultOptions, encode)
|
||||||
import Data.ByteString.Lazy (ByteString)
|
import Data.ByteString.Lazy (ByteString)
|
||||||
import Data.Map (Map, mapWithKey)
|
import Data.Map (Map, mapWithKey)
|
||||||
import qualified Data.Map as Map (filter, keys)
|
import qualified Data.Map as Map (filter, keys)
|
||||||
import qualified Data.Set as Set (elems, member)
|
import qualified Data.Set as Set (elems, member)
|
||||||
|
import Data.Text (Text)
|
||||||
|
import Data.Text.Template (showTemplate)
|
||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
|
|
||||||
data ArticleExport = ArticleExport {
|
data ArticleExport = ArticleExport {
|
||||||
|
@ -43,11 +45,25 @@ data SkinExport = SkinExport {
|
||||||
instance ToJSON SkinExport where
|
instance ToJSON SkinExport where
|
||||||
toEncoding = genericToEncoding defaultOptions
|
toEncoding = genericToEncoding defaultOptions
|
||||||
|
|
||||||
|
data WordingExport = WordingExport {
|
||||||
|
allLink :: Text
|
||||||
|
, allPage :: Text
|
||||||
|
, allTaggedPage :: Text
|
||||||
|
, latestLink :: Text
|
||||||
|
, latestPage :: Text
|
||||||
|
, latestTaggedPage :: Text
|
||||||
|
, tagsList :: Text
|
||||||
|
} deriving (Generic)
|
||||||
|
|
||||||
|
instance ToJSON WordingExport where
|
||||||
|
toEncoding = genericToEncoding defaultOptions
|
||||||
|
|
||||||
data BlogDB = BlogDB {
|
data BlogDB = BlogDB {
|
||||||
articles :: Map String ArticleExport
|
articles :: Map String ArticleExport
|
||||||
, path :: PathExport
|
, path :: PathExport
|
||||||
, skin :: SkinExport
|
, skin :: SkinExport
|
||||||
, tags :: Map String [String]
|
, tags :: Map String [String]
|
||||||
|
, wording :: WordingExport
|
||||||
} deriving (Generic)
|
} deriving (Generic)
|
||||||
|
|
||||||
instance ToJSON BlogDB where
|
instance ToJSON BlogDB where
|
||||||
|
@ -76,4 +92,13 @@ exportBlog = do
|
||||||
, previewLinesCount = Blog.previewLinesCount $ Blog.skin blog
|
, previewLinesCount = Blog.previewLinesCount $ Blog.skin blog
|
||||||
}
|
}
|
||||||
, tags = Set.elems <$> Blog.tags blog
|
, tags = Set.elems <$> Blog.tags blog
|
||||||
|
, wording = WordingExport {
|
||||||
|
allLink = Blog.allLink $ Blog.wording blog
|
||||||
|
, allPage = Blog.allPage $ Blog.wording blog
|
||||||
|
, allTaggedPage = showTemplate . Blog.allTaggedPage $ Blog.wording blog
|
||||||
|
, latestLink = Blog.latestLink $ Blog.wording blog
|
||||||
|
, latestPage = Blog.latestPage $ Blog.wording blog
|
||||||
|
, latestTaggedPage = showTemplate . Blog.latestTaggedPage $ Blog.wording blog
|
||||||
|
, tagsList = Blog.tagsList $ Blog.wording blog
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue