-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsite.hs
189 lines (163 loc) · 6.05 KB
/
site.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
--------------------------------------------------------------------------------
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
import qualified Control.Applicative as A
import Data.Char (isDigit)
import Data.List (isInfixOf)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>), First(..))
import Data.Time (iso8601DateFormat)
import Debug.Trace
import Hakyll
import qualified Data.Set
import Text.Pandoc.Options (WriterOptions(..))
import Text.Pandoc.Extensions (Extension(Ext_smart), disableExtension)
import System.FilePath
(joinPath, splitFileName, splitPath, dropFileName, (-<.>))
--------------------------------------------------------------------------------
main :: IO ()
main =
hakyll $ do
match "favicon.ico" $ do
route idRoute
compile copyFileCompiler
match "google*.html" $ do
route idRoute
compile copyFileCompiler
match "images/*" $ do
route idRoute
compile copyFileCompiler
match "css/*" $ do
route idRoute
compile compressCssCompiler
match (fromList ["about.markdown"]) $ do
route $ constRoute "about/index.html"
compile $
pandocCompiler >>=
loadAndApplyTemplate "templates/default.html" baseContext >>=
relativizeUrls >>=
removeIndexHtml
match "posts/*/index.*" $ do
route postRoute
compile $
pandocCompilerWith defaultHakyllReaderOptions myHakyllWriterOptions >>=
loadAndApplyTemplate "templates/post.html" postCtx >>=
saveSnapshot "feed" >>=
loadAndApplyTemplate "templates/default.html" postCtx >>=
relativizeUrls >>=
removeIndexHtml
match "drafts/*/index.*" $ do
route postRoute
let ctx = noIndex postCtx
compile $
pandocCompilerWith defaultHakyllReaderOptions myHakyllWriterOptions >>=
loadAndApplyTemplate "templates/post.html" ctx >>=
loadAndApplyTemplate "templates/default.html" ctx >>=
relativizeUrls >>=
removeIndexHtml
match "index.html" $ do
route idRoute
compile $ do
posts <- recentFirst =<< loadAll "posts/*/index.*"
let indexCtx = listField "posts" postCtx (return posts) <> baseContext
getResourceBody >>= applyAsTemplate indexCtx >>=
loadAndApplyTemplate "templates/default.html" indexCtx >>=
relativizeUrls >>=
removeIndexHtml
match "templates/*" $ compile templateCompiler
create ["atom.xml"] $ do
route idRoute
compile $ do
let feedCtx = bodyField "description" `mappend` postCtx
posts <-
fmap (take 10) . recentFirst =<<
loadAllSnapshots "posts/*/index.*" "feed"
renderAtom atomConfiguration feedCtx posts
--------------------------------------------------------------------------------
-- |Create a Context with key and value given by the functino f applied to
-- the item metadata. If f returns Nothing an empty field will be created
withMetaContext :: String -> (Metadata -> Maybe String) -> Context String
withMetaContext key f =
Context $ \k args i ->
if k == key
then getField i
else A.empty
where
getField item = do
meta <- getMetadata (itemIdentifier item)
case f meta of
(Just value) -> return (StringField value)
_ -> A.empty
-- |Create a key in the context, setting its value from metadata.
-- defaultKeys will be searched in the metadata using the first one
-- that is present. The defaultValue is a last alternative.
-- If no matching keys are found in the metadata and defaultValue == Nothing
-- an empty attribute is created
metaDefaultContext :: String -> [String] -> Maybe String -> Context String
metaDefaultContext key defaultKeys defaultValue = withMetaContext key getKey
where
getKey :: Metadata -> Maybe String
getKey meta = foldr1 (A.<|>) options
where
options =
map (`lookupString` meta) (key : defaultKeys) ++ [defaultValue]
defaultDescription :: String
defaultDescription =
"My personal blog. I write mostly about programming, particularly Haskell and other functional languages"
defaultTitle :: String
defaultTitle = "Sebastian Galkin's Blog"
baseContext :: Context String
baseContext =
metaDefaultContext
"meta-description"
["description"]
(Just defaultDescription) <>
metaDefaultContext "meta-title" ["title"] (Just defaultTitle) <>
mapContext removeIndexStr (urlField "canonicalUrl") <>
defaultContext
baseUrl :: String
baseUrl = "https://blog.sebastian-galkin.com"
postCtx :: Context String
postCtx =
dateField "date" "%B %e, %Y" <>
dateField "isoDate" (iso8601DateFormat Nothing) <>
baseContext
noIndex :: Context a -> Context a
noIndex = (boolField "noindex" (const True) <>)
atomConfiguration :: FeedConfiguration
atomConfiguration =
FeedConfiguration
{ feedTitle = defaultTitle
, feedDescription = defaultDescription
, feedAuthorName = "Sebastian Galkin"
, feedAuthorEmail = "paraseba@gmail.com"
, feedRoot = baseUrl
}
-- based on code from http://yannesposito.com/Scratch/en/blog/Hakyll-setup/
-- replace a 2015-12-25-foo/index.markdown by foo/index.html
postRoute :: Routes
postRoute = customRoute createIndexRoute
where
createIndexRoute = (-<.> "html") . mapPath cleanup . toFilePath
cleanup = dropWhile unwanted
unwanted c = any ($c) [(== '-'), (== '_'), isDigit]
mapPath :: (String -> String) -> FilePath -> FilePath
mapPath f = joinPath . map f . splitPath
-- taken from http://yannesposito.com/Scratch/en/blog/Hakyll-setup/
-- replace url of the form foo/bar/index.html by foo/bar
removeIndexHtml :: Item String -> Compiler (Item String)
removeIndexHtml item = return $ fmap (withUrls removeIndexStr) item
removeIndexStr :: String -> String
removeIndexStr url =
case splitFileName url of
(dir, "index.html")
| isLocal dir -> dir
_ -> url
where
isLocal uri = not (isInfixOf "://" uri)
myHakyllWriterOptions :: WriterOptions
myHakyllWriterOptions = defaultHakyllWriterOptions
{writerExtensions = extensions}
where
extensions =
disableExtension Ext_smart $ writerExtensions defaultHakyllWriterOptions