Skip to the content.
defmodule LiterateCompiler.Outputter.HTML do

    alias Phoenix.HTML

Purpose

is the outputter for HTML - if you want to use GitHub pages use the markdown outputter and GitHub will feed that into Jekyll for you

The fixed API could have been enforced as a behaviour but that’s a bit over the top

Public API

This module decorates the code snippets with classes to use with code highlighters


    def format({:markdown, level}, print_type, "```" <> contents, _language)  when level <= print_type  do
        trimmed = String.trim(contents, "```")
        {:safe, safe} = HTML.html_escape(trimmed)
        "<div class='our_pre'>" <> List.to_string(safe) <> "</div>"
    end
	def format({:markdown, level}, print_type, contents, _language)  when level <= print_type  do
		:markdown.conv_utf8(contents)
	end
    def format({:markdown, _}, _print_type, contents, _language) do
        css_extension = ""
        format_as_code(contents, css_extension)
    end
    def format({:code, _}, _print_level, "\r", _language), do: ""
	def format({:code, _}, _print_level, contents, language) do
        trimmed = String.trim(contents)
		css_extension = Kernel.apply(language, :get_css_ext, [])
        format_as_code(trimmed, css_extension)
	end

We just build a webpage in sections as you would expect and then join them


	def wrap(contents) do
		Enum.join([
					"<html>\n",
					"<head>\n",
                    "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />",
                    setup_highlight(),
					css(),
					"</head>\n",
					"<body>\n",
					contents,
					"</body>\n",
                    run_highlight(),
					"</html>"
				])
	end

Private Fns


    def format_as_code(contents, ext) do
        Enum.join(["<pre><code class=\"language-", ext, "\">\n", contents, "</code></pre>\n"])
    end

These functions generate inline CSS, the external JS on the pages and also

the final invocation of javascript to apply code highlighting

The highlight.js function adds a complete minified js library for code hightlighting to every page

If you are development minded you might want to optimise that.

An alternative option would be to create a minified library and host it somewhere but…

    defp run_highlight() do
        "<script>hljs.highlightAll();</script>"
    end

    defp setup_highlight() do
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
    <script src="./highlight.min.js"></script>
    end

	defp css() do
<style>
html, body {
    padding: 2.5em;
    margin: auto;
    max-width: 98%;
}

body {
    font: 1.3em Palatino, Times;
    color: #333;
    line-height: 1.3;
}

img {
    max-width: 100%;
}

table {
    border-collapse: collapse;
    margin-block-end: 1em;
}

th, td {
    padding: 0.5em 0.5em 0.25em;
    border: 1px solid #DDD;
}

th {
    border-bottom-width: 1.5px;
}

h1, h2, h3, h4, h5, h6 {
    page-break-after: avoid;
}

/* Typography
-------------------------------------------------------- */

h1 {
    margin-top: 0;
    font-weight: normal;
    text-align: center;
}

h2 {
    font-weight: normal;
    margin-top: 1.5em;
}

h3 {
    font-weight: normal;
    font-style: italic;
    margin-top: 1.5em;
}

p {
    margin-top: 0;
    -webkit-hypens: auto;
    -moz-hypens: auto;
    hyphens: auto;
}

ul {
    list-style: square;
    padding-left: 1.2em;
}

ol {
    padding-left: 1.2em;
}

blockquote {
    margin-left: 1em;
    padding-left: 1em;
    border-left: 1px solid #DDD;
}

.our_pre {
    font-family: "Consolas", "Menlo", "Monaco", monospace, serif;
    font-size: 0.9em;
    white-space: pre;
    background: #f3f3f3;
    color: #444;
    display: block;
    overflow-x: auto;
    padding: 1em;
}
code {
    font-family: "Consolas", "Menlo", "Monaco", monospace, serif;
    font-size: 0.9em;
}

a {
    color: #2484c1;
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

a img {
    border: none;
}

h1 a, h1 a:hover {
    color: #333;
    text-decoration: none;
}

hr {
    color: #DDD;
    height: 1px;
    margin: 2em 0;
    border-top: solid 1px #DDD;
    border-bottom: none;
    border-left: 0;
    border-right: 0;
}


/* Small screens
-------------------------------------------------------- */

@media only screen and (max-width: 900px) {
    html, body {
        padding-left: 1.2em;
        padding-right: 1.2em;
    }

    body {
        text-align: left;
    }
}

/* Code Formatting
-------------------------------------------------------- */

pre[class*="language-"] {
    overflow-wrap: break-word;
}
</style>
end

end