
70 changed files with 2258 additions and 2095 deletions
@ -0,0 +1 @@ |
|||
system |
@ -1 +1,6 @@ |
|||
--- |
|||
title: 404 Not Found |
|||
layout: page |
|||
--- |
|||
|
|||
The field you were looking for has browned and vanished. |
|||
|
@ -1 +1 @@ |
|||
$body$ |
|||
{{body}} |
|||
|
@ -1,35 +1,33 @@ |
|||
--- |
|||
layout: skeleton |
|||
--- |
|||
{{@layout "skeleton"}} |
|||
<header class="page-header"> |
|||
<div class="content-bound"> |
|||
<div class="logo-icon"><a href="/"></a></div> |
|||
<div class="logo-nav"> |
|||
<h1 class="logo"><a href="/">This Field Was Green</a></h1> |
|||
$partial("_partials/main-nav.html")$ |
|||
{{partial "main-nav"}} |
|||
</div> |
|||
</div> |
|||
</header> |
|||
|
|||
<main class="page-content"> |
|||
<div class="content-bound"> |
|||
$body$ |
|||
{{body}} |
|||
</div> |
|||
</main> |
|||
|
|||
<footer class="page-footer"> |
|||
<div class="content-bound"> |
|||
$partial("_partials/main-nav.html")$ |
|||
{{partial "main-nav"}} |
|||
<p class="copyright">Copyright © <span class="copyright-date">2012</span> Logan McGrath. All rights reserved.</p> |
|||
<p class="generated"> |
|||
Site proudly generated by <a href="http://jaspervdj.be/hakyll">Hakyll</a>. |
|||
This page was rendered from |
|||
$if(sourceFileName)$ |
|||
<a href="$gitWebUrl$/blob/$gitSha1$/$sourceFilePath$">$sourceFileName$</a> |
|||
$else$ |
|||
{{#if gitFileName}} |
|||
<a href="{{gitWebUrl}}/blob/{{gitSha1}}/{{gitFilePath}}">{{gitFileName}}</a> |
|||
{{#else}} |
|||
derived data |
|||
$endif$ |
|||
at commit <a class="commit-link" href="$gitWebUrl$/commit/$gitSha1$">[$gitSha1$] $gitMessage$</a>$if(isChanged)$ with local changes$endif$. |
|||
{{#end}} |
|||
at commit <a class="commit-link" href="{{gitWebUrl}}/commit/{{gitSha1}}">[{{gitSha1}}] {{gitMessage}}</a>{{#if isChanged}} with local changes{{#end}}. |
|||
</p> |
|||
</div> |
|||
</footer> |
|||
|
@ -1,5 +1,3 @@ |
|||
--- |
|||
layout: default |
|||
--- |
|||
<h1 class="page-title">$title$</h1> |
|||
$body$ |
|||
{{@layout "default"}} |
|||
<h1 class="page-title">{{title}}</h1> |
|||
{{body}} |
|||
|
@ -1,20 +1,17 @@ |
|||
--- |
|||
layout: default |
|||
body-class: post-page |
|||
--- |
|||
{{@layout "default"}} |
|||
<article class="post"> |
|||
<header class="post-header"> |
|||
<h1 class="post-title page-title"><a href="$url$">$title$</a></h1> |
|||
<h1 class="post-title page-title"><a href="{{url}}">{{title}}</a></h1> |
|||
<p class="post-published"> |
|||
$if(published)$ |
|||
Posted on $published(shortDate)$ |
|||
$else$ |
|||
Drafted on $date(shortDate)$ |
|||
$endif$ |
|||
$if(author)$ |
|||
by $author$ |
|||
$endif$ |
|||
{{#if published}} |
|||
Posted on {{published | dateAs shortDate}} |
|||
{{#else}} |
|||
Drafted on {{date | dateAs shortDate}} |
|||
{{#end}} |
|||
{{#if author}} |
|||
by {{author}} |
|||
{{#end}} |
|||
</p> |
|||
</header> |
|||
$body$ |
|||
{{body}} |
|||
</article> |
|||
|
@ -1,6 +1,6 @@ |
|||
<nav class="main-nav"> |
|||
<a href='$getRoute("index.html")$'>Home</a> |
|||
<a href='$getRoute("blog/index.html")$'>Blog</a> |
|||
<a href='$getRoute("resume.md")$'>Resume</a> |
|||
<a href='$getRoute("contact.md")$'>Contact</a> |
|||
<a href="{{route 'index.html'}}">Home</a> |
|||
<a href="{{route 'blog/index.html'}}">Blog</a> |
|||
<a href="{{route 'resume.md'}}">Resume</a> |
|||
<a href="{{route 'contact.md'}}">Contact</a> |
|||
</nav> |
|||
|
@ -1,7 +1,7 @@ |
|||
<ul> |
|||
$for(posts)$ |
|||
{{#for posts}} |
|||
<li> |
|||
<a href="$url$">$title$</a> - $date$ |
|||
<a href="{{url}}">{{title}}</a> - {{date}} |
|||
</li> |
|||
$endfor$ |
|||
{{#end}} |
|||
</ul> |
|||
|
@ -1 +1 @@ |
|||
$body$ |
|||
{{body}} |
|||
|
@ -1,10 +1,12 @@ |
|||
<aside id="$imgId$-aside" class="image"> |
|||
<aside {{#if id}}id="{{id}}-aside" {{#end}}class="image"> |
|||
<figure> |
|||
<a href="$imgSrc$" class="image-link"> |
|||
<img id="$imgId$" src="$imgSrc$" title="$imgTitle$" alt="$imgAlt$"> |
|||
<a href="{{src}}" class="image-link"> |
|||
<img src="{{src}}" {{#if id}}id="{{id}}"{{#end}} |
|||
{{#if title}}title="{{title}}"{{#end}} |
|||
{{#if alt}}alt="{{alt}}"{{#end}}> |
|||
</a> |
|||
</figure> |
|||
$if(imgTitle)$ |
|||
<figcaption>$imgTitle$</figcaption> |
|||
$endif$ |
|||
{{#if title}} |
|||
<figcaption>{{title}}</figcaption> |
|||
{{#end}} |
|||
</aside> |
|||
|
@ -1,4 +1,4 @@ |
|||
# Generated from commit $gitSha1$ |
|||
# Generated from commit {{gitSha1}} |
|||
User-agent: * |
|||
Disallow: $siteRoot$/drafts/* |
|||
Sitemap: $siteRoot$/sitemap.xml |
|||
Disallow: {{siteRoot}}/drafts/* |
|||
Sitemap: {{siteRoot}}/sitemap.xml |
|||
|
@ -1,14 +1,14 @@ |
|||
<aside $if(youtubeAsideId)$id="$youtubeAsideId$"$endif$ class="youtube"> |
|||
<aside class="youtube"{{#if id}} id="{{id}}"{{#end}}> |
|||
<figure> |
|||
<iframe src="https://www.youtube.com/embed/$youtubeVideoId$" |
|||
$if(youtubeVideoTitle)$title="$youtubeVideoTitle$"$endif$ |
|||
<iframe src="https://www.youtube.com/embed/{{video}}" |
|||
{{#if title}}title="{{video}}"{{#end}} |
|||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" |
|||
allowfullscreen> |
|||
</iframe> |
|||
</figure> |
|||
$if(youtubeVideoTitle)$ |
|||
{{#if title}} |
|||
<figcaption> |
|||
$youtubeVideoTitle$ |
|||
{{title}} |
|||
</figcaption> |
|||
$endif$ |
|||
{{#end}} |
|||
</aside> |
|||
|
@ -1,9 +1,9 @@ |
|||
--- |
|||
layout: page |
|||
title: "These Posts Were Green" |
|||
updated: 2021-05-24T20:07:11-05:00 |
|||
layout: page.html |
|||
--- |
|||
|
|||
Here you can find all my previous posts: |
|||
|
|||
$partial("_partials/post-list.html")$ |
|||
{{partial "post-list.html"}} |
|||
|
@ -1,8 +1,8 @@ |
|||
--- |
|||
layout: page |
|||
title: "These Drafts Are Still Green" |
|||
updated: 2021-05-24T20:07:11-05:00 |
|||
layout: page.html |
|||
--- |
|||
|
|||
Here you can find all my drafts: |
|||
$partial("_partials/post-list.html")$ |
|||
{{partial "post-list.html"}} |
|||
|
@ -1,32 +1,32 @@ |
|||
--- |
|||
layout: default |
|||
title: "Blogging About Life and Tech" |
|||
updated: $latestPostDate$ |
|||
body-class: blog |
|||
updated: {{latestPostDate}} |
|||
bodyClass: blog |
|||
layout: page.html |
|||
--- |
|||
|
|||
<header> |
|||
<h1 class="page-title">$title$ -- Latest Posts</h1> |
|||
<h1 class="page-title">{{title}} -- Latest Posts</h1> |
|||
</header> |
|||
|
|||
<article class="post latest-post"> |
|||
<header class="post-header"> |
|||
<h1 class="post-title"><a href="$latestPostUrl$">$latestPostTitle$</a></h1> |
|||
<h1 class="post-title"><a href="{{latestPostUrl}}">{{latestPostTitle}}</a></h1> |
|||
<div class="post-published"> |
|||
<p> |
|||
This latest post |
|||
$if(latestPostPublished)$ |
|||
published on $latestPostPublished$ |
|||
$else$ |
|||
drafted on $latestPostDate$ |
|||
$endif$ |
|||
$if(latestPostAuthor)$ |
|||
by $latestPostAuthor$ |
|||
$endif$ |
|||
{{#if latestPostPublished}} |
|||
published on {{latestPostPublished}} |
|||
{{#else}} |
|||
drafted on {{latestPostDate}} |
|||
{{#end}} |
|||
{{#if latestPostAuthor}} |
|||
by {{latestPostAuthor}} |
|||
{{#end}} |
|||
</p> |
|||
</div> |
|||
</header> |
|||
$latestPostBody$ |
|||
{{latestPostBody}} |
|||
</article> |
|||
|
|||
$partial("_partials/teaser-list.html")$ |
|||
{{partial "teaser-list.html"}} |
|||
|
@ -1,5 +1,8 @@ |
|||
{{@ layout "page.html" }} |
|||
--- |
|||
title: Contact Me |
|||
layout: page |
|||
--- |
|||
|
|||
I live in a tiramisรน and have pudding in my ears. Please contact me via {{ mailto authorEmail }} and I shall free my eyes to read and reply heartily; my fingers typing though they have been soaking like biscuits in espresso and cream. I welcome conversations and questions about what I do and I might even ask a few questions of my own, but I do not know how I came to be floating in mascarpone. |
|||
I live in a tiramisรน and have pudding in my ears. Please contact me via <a href="mailto:{{authorEmail}}">{{authorEmail}}</a> and I shall free my eyes to read and reply heartily; my fingers typing though they have been soaking like biscuits in espresso and cream. I welcome conversations and questions about what I do and I might even ask a few questions of my own, but I do not know how I came to be floating in mascarpone. |
|||
|
|||
{{ partial "employment.html" }} |
|||
{{partial "employment"}} |
|||
|
@ -1,7 +1,7 @@ |
|||
--- |
|||
title: "Mowing My Technical Lawn" |
|||
bodyClass: homepage |
|||
layout: page |
|||
body-class: homepage |
|||
--- |
|||
$partial("_partials/about-me.html")$ |
|||
$partial("_partials/teaser-list.html")$ |
|||
{{partial "about-me"}} |
|||
{{partial "teaser-list"}} |
|||
|
@ -1 +1,6 @@ |
|||
Please see my [LinkedIn profile]({{ linkedInProfile }}) for my employment history. |
|||
--- |
|||
title: My Resume |
|||
layout: page |
|||
--- |
|||
|
|||
Please see my [LinkedIn profile]({{linkedInProfile}}) for my employment history. |
|||
|
@ -1,103 +0,0 @@ |
|||
module Green.Context |
|||
( module Green.Context, |
|||
module Green.Context.DateFields, |
|||
module Green.Context.GitCommits, |
|||
) |
|||
where |
|||
|
|||
import Data.String.Utils (endswith) |
|||
import Green.Common |
|||
import Green.Config |
|||
import Green.Context.DateFields |
|||
import Green.Context.GitCommits |
|||
import Green.Template |
|||
import Green.Util (dropIndex, stripSuffix) |
|||
import Hakyll.Web.Html (escapeHtml) |
|||
|
|||
baseContext :: SiteConfig -> Context String |
|||
baseContext config = |
|||
mconcat |
|||
[ constField "siteTitle" (config ^. siteTitle), |
|||
constField "siteRoot" (config ^. siteRoot), |
|||
constField "linkedInProfile" (config ^. siteLinkedInProfile), |
|||
constField "authorEmail" (config ^. siteAuthorEmail), |
|||
trimmedUrlField "url", |
|||
dateFields config, |
|||
gitCommits config, |
|||
imgField, |
|||
youtubeField, |
|||
getRouteField, |
|||
defaultContext, |
|||
linkedTitleField, |
|||
getCodeField |
|||
] |
|||
|
|||
-- | Trims @index.html@ from @$url$@'s |
|||
trimmedUrlField :: String -> Context String |
|||
trimmedUrlField = mapField dropIndex . urlField |
|||
|
|||
siteRootField :: String -> Context String |
|||
siteRootField = constField "siteRoot" |
|||
|
|||
getCodeField :: Context String |
|||
getCodeField = constField "getCode" f |
|||
where |
|||
f :: FunctionValue String String String |
|||
f contentsPath _ _ = trimStartEndLines <$> (tryLoad codeId <|> tryLoad fileId) |
|||
where |
|||
codeId = fromFilePath $ "code/" ++ contentsPath |
|||
fileId = fromFilePath contentsPath |
|||
tryLoad = fmap itemBody . compilePandoc <=< load |
|||
trimStartEndLines = |
|||
unlines |
|||
. reverse |
|||
. dropWhile null |
|||
. reverse |
|||
. dropWhile null |
|||
. lines |
|||
|
|||
imgField :: Context String |
|||
imgField = constField "img" f |
|||
where |
|||
templatePath = "_templates/image.html" |
|||
f :: FunctionValue String String String |
|||
f src context _ = do |
|||
let context' = constField "src" src <> context |
|||
template <- load templatePath |
|||
applied <- applyAsTemplate context' template |
|||
return $ itemBody applied |
|||
|
|||
youtubeField :: Context String |
|||
youtubeField = constField "youtube" f |
|||
where |
|||
templatePath = "_templates/youtube.html" |
|||
f :: FunctionValue String String String |
|||
f videoId context _ = do |
|||
let context' = constField "videoId" videoId <> context |
|||
template <- load templatePath |
|||
rendered <- applyAsTemplate context' template |
|||
return $ itemBody rendered |
|||
|
|||
getRouteField :: Context String |
|||
getRouteField = constField "route" f |
|||
where |
|||
f :: FunctionValue String String String |
|||
f filePath _ _ = do |
|||
let id' = fromFilePath filePath |
|||
getRoute id' >>= \case |
|||
Just r -> return $ "/" ++ stripSuffix "index.html" r |
|||
Nothing -> error $ "no route to " ++ show id' |
|||
|
|||
linkedTitleField :: Context String |
|||
linkedTitleField = constField "linkedTitle" f |
|||
where |
|||
f :: FunctionValue String String String |
|||
f filePath context _ = do |
|||
linkedItem <- load (fromFilePath filePath) |
|||
makeLink <$> getField "title" linkedItem <*> getField "url" linkedItem |
|||
where |
|||
getField key = intoString <=< unContext context key |
|||
makeLink title url |
|||
| endswith ".html" filePath = "<a href=\"" ++ url ++ "\">" ++ escapeHtml title ++ "</a>" |
|||
| endswith ".md" filePath = "[" ++ escapeHtml title ++ "](" ++ url ++ ")" |
|||
| otherwise = title ++ " <" ++ url ++ ">" |
@ -1,106 +0,0 @@ |
|||
module Green.Context.DateFields (dateFields) where |
|||
|
|||
import Data.List (tails) |
|||
import Data.String.Utils |
|||
import Green.Common |
|||
import Green.Config |
|||
import Green.Template.Context |
|||
import Green.Util |
|||
import qualified Hakyll as H |
|||
|
|||
dateFields :: SiteConfig -> Context a |
|||
dateFields config = |
|||
mconcat fields |
|||
<> longDateFormatField |
|||
<> shortDateFormatField |
|||
<> timeFormatField |
|||
where |
|||
fields = uncurry mkFields <$> fieldKeys |
|||
mkFields f k = f timeLocale k |
|||
fieldKeys = |
|||
[ (dateField, "date"), |
|||
(publishedField, "published"), |
|||
(updatedField, "updated") |
|||
] |
|||
timeLocale = config ^. siteTimeLocale |
|||
longDateFormatField = constField "longDate" $ displayFormat ^. displayDateLongFormat |
|||
shortDateFormatField = constField "shortDate" $ displayFormat ^. displayDateShortFormat |
|||
timeFormatField = constField "timeOnly" $ displayFormat ^. displayTimeFormat |
|||
displayFormat = config ^. siteDisplayFormat |
|||
|
|||
dateField :: TimeLocale -> String -> Context a |
|||
dateField = mconcat . (fns <*>) . pure |
|||
where |
|||
fns = [dateField' ["published", "date"], dateFromFilePathField] |
|||
|
|||
publishedField :: TimeLocale -> String -> Context a |
|||
publishedField = dateField' ["published"] |
|||
|
|||
updatedField :: TimeLocale -> String -> Context a |
|||
updatedField = dateField' ["updated"] |
|||
|
|||
dateField' :: forall a. [String] -> TimeLocale -> String -> Context a |
|||
dateField' sourceKeys timeLocale targetKey = constField targetKey f |
|||
where |
|||
f :: FunctionValue String String a |
|||
f dateFormat _ item = do |
|||
maybeDate <- dateFromMetadata sourceKeys timeLocale item |
|||
let maybeFormatted = formatTime timeLocale dateFormat <$> maybeDate |
|||
maybe notFound return maybeFormatted |
|||
notFound = noResult $ "Could not find date field field " ++ show targetKey ++ " from metadata keys " ++ show sourceKeys |
|||
|
|||
dateFromMetadata :: [String] -> TimeLocale -> Item a -> Compiler (Maybe LocalTime) |
|||
dateFromMetadata sourceKeys timeLocale item = do |
|||
maybeDates <- mapM findDate sourceKeys |
|||
return $ firstMaybe maybeDates |
|||
where |
|||
id' = itemIdentifier item |
|||
tryParseDate' = tryParseDate timeLocale metadataDateFormats |
|||
findDate sourceKey = do |
|||
maybeString <- H.lookupString sourceKey <$> H.getMetadata id' |
|||
return (tryParseDate' =<< maybeString) |
|||
|
|||
dateFromFilePathField :: forall a. TimeLocale -> String -> Context a |
|||
dateFromFilePathField timeLocale targetKey = constField targetKey f |
|||
where |
|||
f :: FunctionValue String String a |
|||
f dateFormat _ item = maybe notFound return maybeFormatted |
|||
where |
|||
maybeDate = resolveDateFromFilePath timeLocale item |
|||
maybeFormatted = formatTime timeLocale dateFormat <$> maybeDate |
|||
notFound = noResult $ "Could not find " ++ show targetKey ++ " from file path " ++ show filePath |
|||
filePath = toFilePath (itemIdentifier item) |
|||
|
|||
resolveDateFromFilePath :: TimeLocale -> Item a -> Maybe LocalTime |
|||
resolveDateFromFilePath timeLocale item = |
|||
let paths = splitDirectories $ dropExtension $ toFilePath $ itemIdentifier item |
|||
in firstMaybe $ |
|||
dateFromPath |
|||
<$> [take 3 $ split "-" fnCand | fnCand <- reverse paths] |
|||
++ [fnCand | fnCand <- map (take 3) $ reverse $ tails paths] |
|||
where |
|||
dateFromPath = tryParseDate timeLocale ["%Y-%m-%d"] . intercalate "-" |
|||
|
|||
tryParseDate :: (ParseTime a) => TimeLocale -> [String] -> String -> Maybe a |
|||
tryParseDate timeLocale dateFormats = firstMaybe . flip fmap dateFormats . parse |
|||
where |
|||
parse = flip $ parseTimeM True timeLocale |
|||
|
|||
metadataDateFormats :: [String] |
|||
metadataDateFormats = |
|||
[ "%Y-%m-%d", |
|||
"%Y-%m-%dT%H:%M:%S%Z", |
|||
"%Y-%m-%dT%H:%M:%S", |
|||
"%Y-%m-%d %H:%M:%S%Z", |
|||
"%Y-%m-%d %H:%M:%S", |
|||
"%a, %d %b %Y %H:%M:%S %Z", |
|||
"%a, %d %b %Y %H:%M:%S", |
|||
"%B %e, %Y %l:%M %p %EZ", |
|||
"%B %e, %Y %l:%M %p", |
|||
"%b %e, %Y %l:%M %p %EZ", |
|||
"%b %e, %Y %l:%M %p", |
|||
"%B %e, %Y", |
|||
"%B %d, %Y", |
|||
"%b %e, %Y", |
|||
"%b %d, %Y" |
|||
] |
@ -1,69 +1,72 @@ |
|||