hakyll-series (empty) → 0.1.0.1
raw patch · 4 files changed
+205/−0 lines, 4 filesdep +basedep +containersdep +hakyllsetup-changed
Dependencies added: base, containers, hakyll
Files
- LICENSE +21/−0
- Setup.hs +2/−0
- hakyll-series.cabal +92/−0
- src/Hakyll/Web/Series.hs +90/−0
+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2016 Oisin Kidney++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hakyll-series.cabal view
@@ -0,0 +1,92 @@+name: hakyll-series+version: 0.1.0.1+synopsis: Adds series functionality to hakyll+description:+ Module for adding series functionality to hakyll.+ .+ Example <https://oisdk.github.io/hakyll-series/ here>.+ .+ In your posts, provide metadata at the top like so:+ .+ > ---+ > title: something+ > series: things+ > ---+ .+ This will add the following fields to the post:+ .+ [@series@]: The name of the series+ [@seriesLength@]: The total number of posts in the series+ [@seriesCurPos@]: The position of the current post in the series+ [@seriesUrl@]: The URL of the series page+ .+ Using that, in your post template, something like this:+ .+ >+ > $if(series)$+ > <a href="$seriesUrl$">Part $seriesCurPos$ of a $seriesLength$-part series on $series$</a>+ > $endif$+ .+ Will render like this:+ .+ > Part 1 of a 5-part series on things+ .+ Linked to the aggregate page for the series, which would render something like this:+ .+ > Things+ > Part 1: something+ .+ To add it to your blog, add something like this to your @main@:+ .+ > series <- buildSeries "posts/*" (fromCapture "series/*.html")+ >+ > tagsRules series $ \(s:erie) pattrn -> do+ > let title = toUpper s : erie+ > route idRoute+ > compile $ do+ > posts <- chronological =<< loadAll pattrn+ > let ctx = constField "title" title `mappend`+ > listField "posts" postCtx (pure posts) `mappend`+ > defaultContext+ >+ > makeItem ""+ > >>= loadAndApplyTemplate "templates/series.html" ctx+ > >>= loadAndApplyTemplate "templates/default.html" ctx+ > >>= relativizeUrls+ .+ To have access to the series context in each post, change the post rule to something like this:+ .+ > match "posts/*" $ do+ > route $ setExtension "html"+ > compile $ pandocCompiler+ > >>= loadAndApplyTemplate "templates/post.html" (postCtxWithSeries series)+ > >>= loadAndApplyTemplate "templates/default.html" (postCtxWithSeries series)+ > >>= relativizeUrls+ .+ Where `postCtxWithSeries` can be something like:+ .+ > postCtxWithSeries :: Tags -> Context String+ > postCtxWithSeries series = seriesField series `mappend` postCtx+ .+ A minimal example is provided in this repo, on top of the default hakyll setup. (it also provides the templates)+build-type: Simple+cabal-version: >= 1.10+homepage: https://github.com/oisdk/hakyll-series+license: MIT+license-file: LICENSE+author: Donnacha Oisín Kidney+copyright: 2016 Donnacha Oisín Kidney+maintainer: mail@doisinkidney.com+category: Web++library+ hs-source-dirs: src+ exposed-modules: Hakyll.Web.Series+ build-depends: base == 4.*+ , hakyll >= 4.8.0+ , containers >= 0.5+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/oisdk/hakyll-series
+ src/Hakyll/Web/Series.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE LambdaCase #-}++-- | Module for adding series functionality to a blog, similar to tags.++module Hakyll.Web.Series+ ( seriesField+ , getSeries+ , buildSeries+ ) where++import Control.Applicative+import Control.Arrow+import Control.Monad+import Data.List (elemIndex)+import qualified Data.Map.Strict as Map+import Data.Monoid+import qualified Data.Set as Set+import Hakyll++-- | Gets the series from an identifier. Similar to 'getTags',+-- except it only accepts one series per identifier.+getSeries :: MonadMetadata m => Identifier -> m (Maybe String)+getSeries = flip getMetadataField "series"++toAlt :: (Foldable f, Alternative m) => f a -> m a+toAlt = getAlt . foldMap pure++infixr 1 >->+(>->) :: Functor f => (a -> f b) -> (b -> c) -> a -> f c+f >-> g = f >>> fmap g++-- | Generates four fields:+--+-- [@series@] The name of the series+--+-- [@seriesLength@] The total number of posts in the series+--+-- [@seriesCurPos@] The position of the current post in the series+--+-- [@seriesUrl@] The URL of the series page++seriesField :: Tags -> Context a+seriesField tags = Context $ const . \case+ "series" -> seriesName+ >-> StringField++ "seriesCurPos" -> itemIdentifier &&& otherPostsInSeries+ >>> sequence+ >>> fmap (uncurry elemIndex)+ >=> toAlt+ >-> succ+ >>> show+ >>> StringField++ "seriesLength" -> otherPostsInSeries+ >-> length+ >>> show+ >>> StringField++ "seriesUrl" -> seriesName+ >=> tagsMakeId tags+ >>> getRoute+ >=> toAlt+ >-> toUrl+ >>> StringField++ _ -> const empty+ where+ seriesName = itemIdentifier+ >>> getSeries+ >=> toAlt+ otherPostsInSeries = seriesName+ >=> flip lookup (tagsMap tags)+ >>> toAlt++-- | Similar to the 'buildTags' function in "Hakyll.Web.Tags", except+-- checks the series field, and can only accept one series per item.+buildSeries :: MonadMetadata m+ => Pattern+ -> (String -> Identifier) -- ^ Function for converting a given series name into an identifier for its page+ -> m Tags+buildSeries pattrn makeId = do+ ids <- getMatches pattrn+ tagMap <- foldM addTags Map.empty ids+ let set' = Set.fromList ids+ inOrder <- (traverse.traverse) sortChronological (Map.assocs tagMap)+ pure $ Tags inOrder makeId (PatternDependency pattrn set')+ where+ addTags tagMap id' =+ maybe tagMap (\k -> Map.insertWith (++) k [id'] tagMap) <$> getSeries id'