This repository was archived by the owner on Aug 27, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathMain.hs
More file actions
236 lines (195 loc) · 7.04 KB
/
Copy pathMain.hs
File metadata and controls
236 lines (195 loc) · 7.04 KB
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import Data.Char (toLower)
import Data.List (isSuffixOf)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Hakyll
import System.Environment
import System.FilePath
import Text.Jasmine
import Text.Pandoc
import qualified Data.ByteString.Lazy.Char8 as C
main :: IO ()
main = getEnvironment >>= (hakyllWith configuration . rules)
sitePort :: Int
sitePort = 4000
supportedLanguages :: [String]
supportedLanguages = [ -- Name here the directories of the programming languages to be supported
"elixir"
, "haskell"
, "functional-full-stack" -- Haskell backend + PureScript frontend
, "java"
, "python"
, "reason"
]
markdownPattern :: Pattern
markdownPattern = filePattern "md"
imagePattern :: Pattern
imagePattern = filePattern "png"
filePattern :: String -> Pattern
filePattern extension = foldl (.||.) (head patterns) (tail patterns)
where
patterns = fmap (\dir -> fromGlob $ "tutorials/" ++ dir ++ "/*/*." ++ extension) supportedLanguages
configuration :: Configuration
configuration =
defaultConfiguration
{ ignoreFile = ignoreFile'
, previewPort = sitePort
}
where
ignoreFile' path =
ignoreFile defaultConfiguration path
|| takeFileName path `elem` ["makefile", "stack.yaml"]
cleanIndexUrls :: Item String -> Compiler (Item String)
cleanIndexUrls = return . fmap (withUrls cleanIndex)
cleanIndexHtmls :: Item String -> Compiler (Item String)
cleanIndexHtmls = return . fmap (replaceAll pattern' replacement)
where
pattern' = "/index.html"
replacement = const "/"
cleanIndex :: String -> String
cleanIndex url
| idx `isSuffixOf` url = take (length url - length idx) url
| otherwise = url
where idx = "index.html"
rules :: [(String, String)] -> Rules ()
rules env = do
let commonCtx = commonContext Blog env
datedCtx = datedContext env
tutorialCtx = tutorialContext env
create ["archive.html"] $ do
route idRoute
compile $ do
tutorials <- recentFirst =<< loadAll markdownPattern
let
title = "Archives"
archiveContext =
listField "tutorials" tutorialCtx (return tutorials)
<> constField "title" title
<> constField "title-list" title
<> commonCtx
makeItem ""
>>= loadAndApplyTemplate "templates/archive.html" archiveContext
>>= loadAndApplyTemplate "templates/default.html" archiveContext
>>= relativizeUrls
>>= cleanIndexUrls
match "tutorials/index.html" $ do
route idRoute
compile $ do
tutorials <- recentFirst =<< loadAll markdownPattern
let
indexContext =
listField "tutorials" tutorialCtx (return tutorials)
<> constField "title" "Home"
<> constField "title-list" ""
<> commonCtx
getResourceBody
>>= applyAsTemplate indexContext
>>= loadAndApplyTemplate "templates/default.html" indexContext
>>= relativizeUrls
>>= cleanIndexUrls
match "tutorials/stylesheets/*" $ do
route idRoute
compile compressCssCompiler
match "tutorials/javascripts/*" $ do
route idRoute
compile compressJsCompiler
match "templates/*" (compile templateCompiler)
match "tutorials/*.png" $ do
route idRoute
compile copyFileCompiler
tags <- buildTags markdownPattern (fromCapture "tutorials/tags/*.html")
tagsRules tags $ \tag pattern -> do
let title = "Posts tagged \"" ++ tag ++ "\""
route idRoute
compile $ do
tutorials <- recentFirst =<< loadAll pattern
let ctx = constField "title" title
`mappend` constField "title-list" title
`mappend` listField "tutorials" tutorialCtx (return tutorials)
`mappend` defaultContext
`mappend` commonCtx
makeItem ""
>>= loadAndApplyTemplate "templates/tag.html" ctx
>>= loadAndApplyTemplate "templates/default.html" ctx
>>= relativizeUrls
match markdownPattern $ do
let
tutorialRoute i = takeDirectory p </> "index.html"
where p = toFilePath i
route (customRoute tutorialRoute)
compile $
tutorialsCompiler
>>= loadAndApplyTemplate "templates/tutorial.html" (tutorialCtxWithTags env tags)
>>= loadAndApplyTemplate "templates/default.html" (tutorialCtxWithTags env tags)
>>= relativizeUrls
>>= cleanIndexUrls
match imagePattern $ do
route idRoute
compile copyFileCompiler
create ["tutorials/sitemap.xml"] $ do
route idRoute
compile $ do
posts <- recentFirst =<< loadAll markdownPattern
let allPosts = return posts
let sitemapCtx = listField "entries" tutorialCtx allPosts
makeItem ("" :: String)
>>= loadAndApplyTemplate "templates/sitemap.xml" sitemapCtx
>>= cleanIndexHtmls
let pumpFeedPosts =
fmap (take 10) . recentFirst =<< loadAll markdownPattern
create ["tutorials/atom.xml"] $ do
route idRoute
compile (pumpFeedPosts >>= renderAtom feedConfiguration datedCtx)
create ["tutorials/rss.xml"] $ do
route idRoute
compile (pumpFeedPosts >>= renderRss feedConfiguration datedCtx)
tutorialCtxWithTags :: [(String, String)] -> Tags -> Context String
tutorialCtxWithTags env tags = do
let tutorialCtx = tutorialContext env
tagsField "tags" tags `mappend` tutorialCtx
feedConfiguration :: FeedConfiguration
feedConfiguration =
FeedConfiguration
{ feedTitle = "Stack Builders' Tutorials"
, feedDescription = "Tutorials about tech Stack Builders consider important to promote"
, feedAuthorName = "Stack Builders"
, feedAuthorEmail = "info@stackbuilders.com"
, feedRoot = "https://stackbuilders.com"
}
data Hero
= Blog
| Post
deriving Show
commonContext :: Hero -> [(String, String)] -> Context String
commonContext hero env =
let
readEnv d key = fromMaybe d $ lookup key env
host = readEnv ("//localhost:" ++ show sitePort) "SITE_ROOT_URL"
protocol = readEnv "http:" "SITE_PROTOCOL"
in
constField "host" host
<> constField "protocol" protocol
<> constField "hero" (map toLower (show hero))
<> defaultContext
datedContext :: [(String, String)] -> Context String
datedContext env = dateField "published" "%B %e, %Y" <> commonContext Post env
tutorialContext :: [(String, String)] -> Context String
tutorialContext env = libs <> datedContext env
where
libs = listFieldWith "libs" libraryContext $ \item -> do
libraries <- getMetadataField' (itemIdentifier item) "libraries"
mapM makeItem (words libraries)
libraryContext = field "lib" (return . itemBody)
tutorialsCompiler :: Compiler (Item String)
tutorialsCompiler = pandocCompilerWith defaultTutorialsReaderOptions defaultHakyllWriterOptions
defaultTutorialsReaderOptions :: ReaderOptions
defaultTutorialsReaderOptions = defaultHakyllReaderOptions
{ readerSmart = False
}
compressJsCompiler :: Compiler (Item String)
compressJsCompiler = do
let minifyJS = C.unpack . minify . C.pack . itemBody
source <- getResourceString
return $ itemSetBody (minifyJS source) source