I have a Happstack program that dynamically converts Markdown documents to HTML using Text.Pandoc:
import qualified Text.Pandoc as Pandoc
...
return $ toResponse $ Pandoc.writeHtml Pandoc.def contents
I.e. Pandoc is returning a Text.Blaze.Html.Html value. (This has a ToMessage instance which means it can be used as a response to a request.)
How do I insert a custom CSS stylesheet into Pandoc's output? What if I want to customise the HTML e.g. by wrapping the <body> contents with some other elements?
When Pandoc's "standalone mode" option is enabled, it uses a template to format the output.
The template and its substitions variables can be set in the writerTemplate and writerVariables members of WriterOptions.
The command line tool has a default set of template it uses. You can see the default template for a format using e.g. pandoc -D html.
When using the library, the default is to use an empty template. You can get the default template programmatically using getDefaultTemplate.
Here's some example code:
import Text.Blaze.Html.Renderer.String
import Text.Pandoc
getHtmlOpts = do
template <- either (error . show) id
`fmap` getDefaultTemplate Nothing "html"
return $ def
{ writerStandalone = True
, writerTemplate = template
, writerVariables = [
("css", "/path/to/style.css"),
("header-includes",
"<style>p { background-color: magenta; }</style>")]
}
main = do
opts <- getHtmlOpts
putStrLn $ renderHtml $ writeHtml opts $ readMarkdown def "..."
You can also write your own template, call it for instance template.html and use the --template template.html option when calling pandoc from the command-line.
The documentation is at https://pandoc.org/MANUAL.html#templates, and the default template (for inspiration) is at https://raw.githubusercontent.com/jgm/pandoc-templates/master/default.html5.
Pandoc, when run from the command line, takes some arguments that allow you to insert something into the <head> tag (-H), before content (-B) and after content (-A). I don't know about Happstack, but surely there must be a way to pass these parameters to Pandoc.writeHtml
Related
I have a directory of xml files in a source directory that I want to turn into a directory of html files in a destination directory. It seems I can use getDirectoryFiles to get files from a directory, but that is an Action, and want needs not an Action [FilePath] but just a [FilePath]. How can I do something like want ["dest/*.html"] in Shake?
If I understand you correctly, you can do like this.
First of all, write a rule that creates the html file from xml.
main = shakeArgs shakeOptions $ do
"dest/*.html" %> \out -> do
let src = "source" </> dropDirectory1 out -<.> "xml"
-- todo: generate out (HTML) from src (XML)
Then you can write a rule by action that will be run in every build execution.
main = shakeArgs shakeOptions $ do
action $ do
srcs <- getDirectoryFiles "source" ["*.xml"]
need ["dest" </> src -<.> "html" | src <- srcs]
"dest/*.html" %> \out -> do
let src = "source" </> dropDirectory1 out -<.> "xml"
-- todo: translate HTML(out) from XML(src)
For your information, want defined like: want xs = action $ need xs.
getDirectoryFiles returns a result in the Action monad, but want returns a result in the Rules monad. You probably meant need instead, which is basically the same as want but in Action. Then just use >>= or do blocks like you would with any other monad:
do
directoryFiles <- getDirectoryFiles path patterns
need directoryFiles
If you want to end up back in Rules after that, then wrap the entire do block in a call to action.
I am using Hakyll to generate my blog and would like to integrate in the generated web site some slides from talks I give. This should be as simple as defining you own custom pandocCompiler with adequate configuration and indeed I manage to do it.
Here is the compiler definition:
pandocSlideCompiler :: Compiler (Item String)
pandocSlideCompiler = pandocCompilerWith defaultHakyllReaderOptions writeHtmlSlide
where
writeHtmlSlide = defaultHakyllWriterOptions { writerIncremental = True
, writerSectionDivs = False
, writerVariables = [("theme", "beige")]
, writerSlideLevel = Just 2
, writerSlideVariant = RevealJsSlides
, writerIgnoreNotes = True
}
This works but the generated slides are not correctly formatted: Each slide is generated as div whereas reveal.js expects a section.
Here is the command-line equivalent I would like to implement:
pandoc --slide-level 2 --variable theme=beige -i -s -o slides.html --template=template-revealjs.html -t revealjs slides.md
My question is then: Which options from Text.Pandoc.Options shall I use to produce the same result as my command-line?
I think you need to add writerHtml5 = True, as can be seen in the pandoc source commandline args parsing and HTML writer...
In a yesod application, I want to create URL attributes for a graph that will be rendered by graphviz , and I want to use interpolation. Ideally,
graphToDot nonClusteredParams { fmtNode = \ (n,l) ->
[ URL [whamlet| #{MyRoute ...} |]
} g
Of course, the types don't match:
attribute of URL is pure Text, but whamlet is monadic (widget)
when I replace by shamlet, type is fine, but it cannot interpolate: URL interpolation used, but no URL renderer provided
Is there an easy way to solve this?
This works: get the render function (in the monad), and apply (in pure code)
render <- getUrlRender
let d = graphToDot ...
[ URL $ render $ MyRoute ... ]
I found this here, where a similar problem is solved: https://github.com/yesodweb/yesod/wiki/Using-type-safe-urls-from-inside-javascript
Is there some way in yesod-0.9.3 to convert Json to Html to include it into <script/> tag?
Using Yesod.Json and Data.Aeson I can get the value of a Json type, which I want to use as the value of a variable introduced in a <script> tag, that is, not to return RepJson, but to include it as a part of RepHtml.
Using fully qualified names...
let txtVal = Data.Text.Lazy.Encoding.decodeUtf8 $ Data.Aeson.encode jsonVal
then, inside your hamlet:
<script>
var v = #{txtVal}
Note that this is a bit dangerous in that it doesn't check that the encoding was successful. Look at the Data.Text.Encoding module for more info.
I can find plenty of documentation on using blitz and other compiletime templating libraries with happstack but I would like to know how to use html files as templates.
Though there are many options, my favourite would be Heist, which would allow you to define a splice:
> factSplice :: (Monad m) => TemplateMonad m Template
> factSplice = do
> input <- getParamNode
> let text = T.unpack $ X.nodeText input
> n = read text :: Int
> return [X.TextNode $ T.pack $ show $ product [1..n]]
>
which could be used in a dynamic (loaded at runtime) HTML template:
<html>
<head>
<title>Factorial Page</title>
</head>
<body>
<h1>Factorial Page</h1>
<p>The factorial of 6 is <fact>6</fact></p>
</body>
</html>
To use heist in happstack, you'll need the happstack-heist package. For more detail and other options, see Using Heist.
The HStringTemplate package provides a very general runtime templating system for not only HTML, but any sort of text output:
http://hackage.haskell.org/packages/archive/HStringTemplate/0.6.6/doc/html/Text-StringTemplate.html
The HStringTemplate package integrates with Happstack nicely through a few extra instances provided by an optional package: http://hackage.haskell.org/package/happstack-hstringtemplate