From 321ac6c77d870a54fcf901423bdc2280bbcac755 Mon Sep 17 00:00:00 2001 From: Raging Raspberries Date: Thu, 4 Nov 2021 19:46:37 +1000 Subject: [PATCH] Initial commit --- .envrc | 2 + .gitignore | 1 + LICENSE | 61 +++ README.rst | 10 + css/base.css | 419 +++++++++++++++++ css/default.css | 141 ++++++ css/jfdic.css | 532 ++++++++++++++++++++++ css/syntax.css | 62 +++ default.nix | 1 + error/404.rst | 12 + hakyll.patch | 0 images/hakyll-logo.svg | 85 ++++ images/haskell-logo.png | Bin 0 -> 5674 bytes index.rst | 5 + jfdic-web.cabal | 14 + jfdic-web.nix | 11 + js/script.js | 15 + nix/sources.json | 26 ++ nix/sources.nix | 134 ++++++ pages/About.rst | 7 + pages/Contact.rst | 5 + posts/2015-08-12-spqr.markdown | 60 +++ posts/2015-10-07-rosa-rosa-rosam.markdown | 47 ++ posts/2015-11-28-carpe-diem.markdown | 51 +++ posts/2015-12-07-tu-quoque.markdown | 59 +++ release.nix | 46 ++ shell.nix | 1 + site.hs | 198 ++++++++ templates/archive.html | 4 + templates/default.html | 33 ++ templates/head.html | 35 ++ templates/index.html | 31 ++ templates/page.html | 4 + templates/post-list.html | 7 + templates/post.html | 31 ++ templates/sidebar.html | 38 ++ 36 files changed, 2188 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.rst create mode 100644 css/base.css create mode 100644 css/default.css create mode 100644 css/jfdic.css create mode 100644 css/syntax.css create mode 100644 default.nix create mode 100644 error/404.rst create mode 100644 hakyll.patch create mode 100644 images/hakyll-logo.svg create mode 100644 images/haskell-logo.png create mode 100644 index.rst create mode 100644 jfdic-web.cabal create mode 100644 jfdic-web.nix create mode 100644 js/script.js create mode 100644 nix/sources.json create mode 100644 nix/sources.nix create mode 100644 pages/About.rst create mode 100644 pages/Contact.rst create mode 100644 posts/2015-08-12-spqr.markdown create mode 100644 posts/2015-10-07-rosa-rosa-rosam.markdown create mode 100644 posts/2015-11-28-carpe-diem.markdown create mode 100644 posts/2015-12-07-tu-quoque.markdown create mode 100644 release.nix create mode 100644 shell.nix create mode 100644 site.hs create mode 100644 templates/archive.html create mode 100644 templates/default.html create mode 100644 templates/head.html create mode 100644 templates/index.html create mode 100644 templates/page.html create mode 100644 templates/post-list.html create mode 100644 templates/post.html create mode 100644 templates/sidebar.html diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..18f695a --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +use nix +watch_file nix/* diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92b2793 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.direnv diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..78d805a --- /dev/null +++ b/LICENSE @@ -0,0 +1,61 @@ + ANARCHIST LICENSE + Version 1.0, 1 May, 2021 + +Copyright © 2021 JFDI Collective + +This is Anarchist software, released for free use by individuals and +organizations that do not operate by capitalist principles. + +Permission is hereby granted, free of charge, to any peaceful non-aggressive +sovereign individual or group of sovereign individuals (the "individual") +obtaining a copy of this software, associated documentation files, and other +forms of information (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: + +1. The above copyright notice and this permission notice shall be included in + all copies or modified versions of the Software. + +2. The User is one of the following: + + a. An individual person, laboring for themselves + b. A non-profit organization + c. An educational institution + d. An organization that seeks shared profit for all of its members, and + allows non-members to set the cost of their labor + +3. If the User is an organization with owners, then all owners are workers and + all workers are owners with equal equity and/or equal vote. + +4. If the User is an organization, then the User is not law enforcement or + military, or working for or under either. + +Any individual breaking the Natural Law of Non-Aggression and Self-Defense is +entirely prohibited to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the software. This includes explicitly but is +not limited to, + +* Any individual engaging in, or encouraging murder, assault, theft, rape, + trespassing, coercion, lying, or any other initiation of aggressive violence + against the private property of peaceful individuals; +* Any officer, contractor, subcontractor, or staff acting on behalf of, or being + funded by any government or law enforcement agency; +* Any officer, contractor, subcontractor, or staff associated with the + investigation of any active criminal proceedings of victimless crimes; +* Any individual relying on monopolistic privilege licenses granted by any + government or law enforcement agency; +* Any officer, contractor, subcontractor, or staff of any surveillance effort + acting in an official and/or commercial capacity or being contracted by any + government or law enforcement agency; +* Any individual investigating "money laundering" or "unexplained wealth"; or +* Any individual aggressively enforcing "intellectual property rights". + +DON'T TRUST, VERIFY. 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. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..6841913 --- /dev/null +++ b/README.rst @@ -0,0 +1,10 @@ +JFDIC Web +========= + +Website configuration for the `JFDI Collective`_. + +The canonical home for this repo is +https://source.jfdic.org/jfdic/jfdic-web + +.. _NixOps: https://nixos.org/nixops +.. _JFDI Collective: https://jfdic.org/ diff --git a/css/base.css b/css/base.css new file mode 100644 index 0000000..a11e818 --- /dev/null +++ b/css/base.css @@ -0,0 +1,419 @@ +/* + * Base CSS + */ + + +/* + * Contents + * + * Body resets + * Custom type + * Messages + * Container + * Masthead + * Posts and pages + * Pagination + * Reverse layout + * Themes + */ + + +/* + * Body resets + * + * Update the foundational and global aspects of the page. + */ + +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; +} + +html { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 1.5; +} +@media (min-width: 38em) { + html { + font-size: 20px; + } +} + +body { + color: #515151; + background-color: #fff; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +/* No `:visited` state is required by default (browsers will use `a`) */ +a { + color: #268bd2; + text-decoration: none; +} +a strong { + color: inherit; +} +/* `:focus` is linked to `:hover` for basic accessibility */ +a:hover, +a:focus { + text-decoration: underline; +} + +/* Headings */ +h1, h2, h3, h4, h5, h6 { + margin-bottom: .5rem; + font-weight: bold; + line-height: 1.25; + color: #313131; + text-rendering: optimizeLegibility; +} +h1 { + font-size: 2rem; +} +h2 { + margin-top: 1rem; + font-size: 1.5rem; +} +h3 { + margin-top: 1.5rem; + font-size: 1.25rem; +} +h4, h5, h6 { + margin-top: 1rem; + font-size: 1rem; +} + +/* Body text */ +p { + margin-top: 0; + margin-bottom: 1rem; +} + +strong { + color: #303030; +} + + +/* Lists */ +ul, ol, dl { + margin-top: 0; + margin-bottom: 1rem; +} + +dt { + font-weight: bold; +} +dd { + margin-bottom: .5rem; +} + +/* Misc */ +hr { + position: relative; + margin: 1.5rem 0; + border: 0; + border-top: 1px solid #eee; + border-bottom: 1px solid #fff; +} + +abbr { + font-size: 85%; + font-weight: bold; + color: #555; + text-transform: uppercase; +} +abbr[title] { + cursor: help; + border-bottom: 1px dotted #e5e5e5; +} + +/* Code */ +code, +pre { + font-family: Menlo, Monaco, "Courier New", monospace; +} +code { + padding: .25em .5em; + font-size: 85%; + color: #bf616a; + background-color: #f9f9f9; + border-radius: 3px; +} +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + padding: 1rem; + font-size: .8rem; + line-height: 1.4; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; + background-color: #f9f9f9; +} +pre code { + padding: 0; + font-size: 100%; + color: inherit; + background-color: transparent; +} + +/* Pygments via Jekyll */ +.highlight { + margin-bottom: 1rem; + border-radius: 4px; +} +.highlight pre { + margin-bottom: 0; +} + +/* Gist via GitHub Pages */ +.gist .gist-file { + font-family: Menlo, Monaco, "Courier New", monospace !important; +} +.gist .markdown-body { + padding: 15px; +} +.gist pre { + padding: 0; + background-color: transparent; +} +.gist .gist-file .gist-data { + font-size: .8rem !important; + line-height: 1.4; +} +.gist code { + padding: 0; + color: inherit; + background-color: transparent; + border-radius: 0; +} + +/* Quotes */ +blockquote { + padding: .5rem 1rem; + margin: .8rem 0; + color: #7a7a7a; + border-left: .25rem solid #e5e5e5; +} +blockquote p:last-child { + margin-bottom: 0; +} +@media (min-width: 30em) { + blockquote { + padding-right: 5rem; + padding-left: 1.25rem; + } +} + +img { + display: block; + max-width: 100%; + margin: 0 0 1rem; + border-radius: 5px; +} + +/* Tables */ +table { + margin-bottom: 1rem; + width: 100%; + border: 1px solid #e5e5e5; + border-collapse: collapse; +} +td, +th { + padding: .25rem .5rem; + border: 1px solid #e5e5e5; +} +tbody tr:nth-child(odd) td, +tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} + + +/* + * Custom type + * + * Extend paragraphs with `.lead` for larger introductory text. + */ + +.lead { + font-size: 1.25rem; + font-weight: 300; +} + + +/* + * Messages + * + * Show alert messages to users. You may add it to single elements like a `

`, + * or to a parent if there are multiple elements to show. + */ + +.message { + margin-bottom: 1rem; + padding: 1rem; + color: #717171; + background-color: #f9f9f9; +} + + +/* + * Container + * + * Center the page content. + */ + +.container { + max-width: 38rem; + padding-left: 1rem; + padding-right: 1rem; + margin-left: auto; + margin-right: auto; +} + + +/* + * Masthead + * + * Super small header above the content for site name and short description. + */ + +.masthead { + padding-top: 1rem; + padding-bottom: 1rem; + margin-bottom: 3rem; +} +.masthead-title { + margin-top: 0; + margin-bottom: 0; + color: #505050; +} +.masthead-title a { + color: #505050; +} +.masthead-title small { + font-size: 75%; + font-weight: 400; + color: #c0c0c0; + letter-spacing: 0; +} + + +/* + * Posts and pages + * + * Each post is wrapped in `.post` and is used on default and post layouts. Each + * page is wrapped in `.page` and is only used on the page layout. + */ + +.page, +.post { + margin-bottom: 4em; +} + +/* Blog post or page title */ +.page-title, +.post-title, +.post-title a { + color: #303030; +} +.page-title, +.post-title { + margin-top: 0; +} + +/* Meta data line below post title */ +.post-date { + display: block; + margin-top: -.5rem; + margin-bottom: 1rem; + color: #9a9a9a; +} + +/* Related posts */ +.related { + padding-top: 2rem; + padding-bottom: 2rem; + border-top: 1px solid #eee; +} +.related-posts { + padding-left: 0; + list-style: none; +} +.related-posts h3 { + margin-top: 0; +} +.related-posts li small { + font-size: 75%; + color: #999; +} +.related-posts li a:hover { + color: #268bd2; + text-decoration: none; +} +.related-posts li a:hover small { + color: inherit; +} + + +/* + * Pagination + * + * Super lightweight (HTML-wise) blog pagination. `span`s are provide for when + * there are no more previous or next posts to show. + */ + +.pagination { + overflow: hidden; /* clearfix */ + margin-left: -1rem; + margin-right: -1rem; + font-family: "PT Sans", Helvetica, Arial, sans-serif; + color: #ccc; + text-align: center; +} + +/* Pagination items can be `span`s or `a`s */ +.pagination-item { + display: block; + padding: 1rem; + border: 1px solid #eee; +} +.pagination-item:first-child { + margin-bottom: -1px; +} + +/* Only provide a hover state for linked pagination items */ +a.pagination-item:hover { + background-color: #f5f5f5; +} + +@media (min-width: 30em) { + .pagination { + margin: 3rem 0; + } + .pagination-item { + float: left; + width: 50%; + } + .pagination-item:first-child { + margin-bottom: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + } + .pagination-item:last-child { + margin-left: -1px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + } +} diff --git a/css/default.css b/css/default.css new file mode 100644 index 0000000..381ff73 --- /dev/null +++ b/css/default.css @@ -0,0 +1,141 @@ +html { + font-size: 62.5%; +} + +body { + font-size: 1.6rem; + color: #000; +} + +header { + border-bottom: 0.2rem solid #000; +} + +nav { + text-align: right; +} + +nav a { + font-size: 1.8rem; + font-weight: bold; + color: black; + text-decoration: none; + text-transform: uppercase; +} + +footer { + margin-top: 3rem; + padding: 1.2rem 0; + border-top: 0.2rem solid #000; + font-size: 1.2rem; + color: #555; +} + +h1 { + font-size: 2.4rem; +} + +h2 { + font-size: 2rem; +} + +article .header { + font-size: 1.4rem; + font-style: italic; + color: #555; +} + +.logo a { + font-weight: bold; + color: #000; + text-decoration: none; +} + +@media (max-width: 319px) { + body { + width: 90%; + margin: 0; + padding: 0 5%; + } + header { + margin: 4.2rem 0; + } + nav { + margin: 0 auto 3rem; + text-align: center; + } + footer { + text-align: center; + } + .logo { + text-align: center; + margin: 1rem auto 3rem; + } + .logo a { + font-size: 2.4rem; + } + nav a { + display: block; + line-height: 1.6; + } +} + +@media (min-width: 320px) { + body { + width: 90%; + margin: 0; + padding: 0 5%; + } + header { + margin: 4.2rem 0; + } + nav { + margin: 0 auto 3rem; + text-align: center; + } + footer { + text-align: center; + } + .logo { + text-align: center; + margin: 1rem auto 3rem; + } + .logo a { + font-size: 2.4rem; + } + nav a { + display: inline; + margin: 0 0.6rem; + } +} + +@media (min-width: 640px) { + body { + width: 60rem; + margin: 0 auto; + padding: 0; + } + header { + margin: 0 0 3rem; + padding: 1.2rem 0; + } + nav { + margin: 0; + text-align: right; + } + nav a { + margin: 0 0 0 1.2rem; + display: inline; + } + footer { + text-align: right; + } + .logo { + margin: 0; + text-align: left; + } + .logo a { + float: left; + font-size: 1.8rem; + } +} diff --git a/css/jfdic.css b/css/jfdic.css new file mode 100644 index 0000000..47b4a24 --- /dev/null +++ b/css/jfdic.css @@ -0,0 +1,532 @@ +/* + * JFDIC theme + */ + +/* + * Global resets + * + * Update the foundational and global aspects of the page. + */ + +/* Prevent scroll on narrow devices */ +html, +body { + overflow-x: hidden; +} + +html { + font-family: "PT Serif", Georgia, "Times New Roman", serif; +} + +h1, h2, h3, h4, h5, h6 { + font-family: "PT Sans", Helvetica, Arial, sans-serif; + font-weight: 400; + color: #313131; + letter-spacing: -.025rem; +} + + +/* + * Wrapper + * + * The wrapper is used to position site content when the sidebar is toggled. We + * use an outter wrap to position the sidebar without interferring with the + * regular page content. + */ + +.wrap { + position: relative; + width: 100%; +} + + +/* + * Container + * + * Center the page content. + */ + +.container { + max-width: 28rem; +} +@media (min-width: 38em) { + .container { + max-width: 32rem; + } +} +@media (min-width: 56em) { + .container { + max-width: 38rem; + } +} + + +/* + * Masthead + * + * Super small header above the content for site name and short description. + */ + +.masthead { + padding-top: 1rem; + padding-bottom: 1rem; + margin-bottom: 3rem; + border-bottom: 1px solid #eee; +} +.masthead-title { + margin-top: 0; + margin-bottom: 0; + color: #505050; +} +.masthead-title a { + color: #505050; +} +.masthead-title small { + font-size: 75%; + font-weight: 400; + color: #c0c0c0; + letter-spacing: 0; +} + +@media (max-width: 48em) { + .masthead-title { + text-align: center; + } + .masthead-title small { + display: none; + } +} + + +/* + * Sidebar + * + * The sidebar is the drawer, the item we are toggling with our handy hamburger + * button in the corner of the page. + * + * This particular sidebar implementation was inspired by Chris Coyier's + * "Offcanvas Menu with CSS Target" article, and the checkbox variation from the + * comments by a reader. It modifies both implementations to continue using the + * checkbox (no change in URL means no polluted browser history), but this uses + * `position` for the menu to avoid some potential content reflow issues. + * + * Source: http://css-tricks.com/off-canvas-menu-with-css-target/#comment-207504 + */ + +/* Style and "hide" the sidebar */ +.sidebar { + position: fixed; + top: 0; + bottom: 0; + left: -14rem; + width: 14rem; + visibility: hidden; + overflow-y: auto; + font-family: "PT Sans", Helvetica, Arial, sans-serif; + font-size: .875rem; /* 15px */ + color: rgba(255,255,255,.6); + background-color: #202020; + -webkit-transition: all .3s ease-in-out; + transition: all .3s ease-in-out; +} +@media (min-width: 30em) { + .sidebar { + font-size: .75rem; /* 14px */ + } +} + +/* Sidebar content */ +.sidebar a { + font-weight: normal; + color: #fff; +} +.sidebar-item { + padding: 1rem; +} +.sidebar-item p:last-child { + margin-bottom: 0; +} + +/* Sidebar nav */ +.sidebar-nav { + border-bottom: 1px solid rgba(255,255,255,.1); +} +.sidebar-nav-item { + display: block; + padding: .5rem 1rem; + border-top: 1px solid rgba(255,255,255,.1); +} +.sidebar-nav-item.active, +a.sidebar-nav-item:hover, +a.sidebar-nav-item:focus { + text-decoration: none; + background-color: rgba(255,255,255,.1); + border-color: transparent; +} + +@media (min-width: 48em) { + .sidebar-item { + padding: 1.5rem; + } + .sidebar-nav-item { + padding-left: 1.5rem; + padding-right: 1.5rem; + } +} + +/* Hide the sidebar checkbox that we toggle with `.sidebar-toggle` */ +.sidebar-checkbox { + position: absolute; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +/* Style the `label` that we use to target the `.sidebar-checkbox` */ +.sidebar-toggle { + position: absolute; + top: .8rem; + left: 1rem; + display: flex; + align-items: center; + padding: .25rem .75rem; + color: #505050; + background-color: #fff; + border-radius: .25rem; + cursor: pointer; +} + +.sidebar-toggle::before { + display: inline-block; + width: 32px; + height: 32px; + content: ""; + background: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' fill='%23555' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' d='M2.5 11.5A.5.5 0 013 11h10a.5.5 0 010 1H3a.5.5 0 01-.5-.5zm0-4A.5.5 0 013 7h10a.5.5 0 010 1H3a.5.5 0 01-.5-.5zm0-4A.5.5 0 013 3h10a.5.5 0 010 1H3a.5.5 0 01-.5-.5z' clip-rule='evenodd'/%3E%3C/svg%3E") no-repeat; +} + +.sidebar-toggle:active, +#sidebar-checkbox:focus ~ .sidebar-toggle, +#sidebar-checkbox:checked ~ .sidebar-toggle { + color: #fff; + background-color: #555; +} + +.sidebar-toggle:active:before, +#sidebar-checkbox:focus ~ .sidebar-toggle::before, +#sidebar-checkbox:checked ~ .sidebar-toggle::before { + background: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' d='M2.5 11.5A.5.5 0 013 11h10a.5.5 0 010 1H3a.5.5 0 01-.5-.5zm0-4A.5.5 0 013 7h10a.5.5 0 010 1H3a.5.5 0 01-.5-.5zm0-4A.5.5 0 013 3h10a.5.5 0 010 1H3a.5.5 0 01-.5-.5z' clip-rule='evenodd'/%3E%3C/svg%3E") no-repeat; +} + +@media (min-width: 30.1em) { + .sidebar-toggle { + position: fixed; + } +} + +@media print { + .sidebar-toggle { + display: none; + } +} + +/* Slide effect + * + * Handle the sliding effects of the sidebar and content in one spot, seperate + * from the default styles. + * + * As an a heads up, we don't use `transform: translate3d()` here because when + * mixed with `position: fixed;` for the sidebar toggle, it creates a new + * containing block. Put simply, the fixed sidebar toggle behaves like + * `position: absolute;` when transformed. + * + * Read more about it at http://meyerweb.com/eric/thoughts/2011/09/12/. + */ + +.wrap, +.sidebar, +.sidebar-toggle { + -webkit-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; +} +.wrap, +.sidebar-toggle { + -webkit-transition: -webkit-transform .3s ease-in-out; + transition: transform .3s ease-in-out; +} + +#sidebar-checkbox:checked + .sidebar { + z-index: 10; + visibility: visible; +} +#sidebar-checkbox:checked ~ .sidebar, +#sidebar-checkbox:checked ~ .wrap, +#sidebar-checkbox:checked ~ .sidebar-toggle { + -webkit-transform: translateX(14rem); + -ms-transform: translateX(14rem); + transform: translateX(14rem); +} + + +/* + * Posts and pages + * + * Each post is wrapped in `.post` and is used on default and post layouts. Each + * page is wrapped in `.page` and is only used on the page layout. + */ + +.page, +.post { + margin-bottom: 4em; +} + +/* Blog post or page title */ +.page-title, +.post-title, +.post-title a { + color: #303030; +} +.page-title, +.post-title { + margin-top: 0; +} + +/* Meta data line below post title */ +.post-date { + display: block; + margin-top: -.5rem; + margin-bottom: 1rem; + color: #9a9a9a; +} + +/* Related posts */ +.related { + padding-top: 2rem; + padding-bottom: 2rem; + border-top: 1px solid #eee; +} +.related-posts { + padding-left: 0; + list-style: none; +} +.related-posts h3 { + margin-top: 0; +} +.related-posts li small { + font-size: 75%; + color: #999; +} +.related-posts li a:hover { + color: #268bd2; + text-decoration: none; +} +.related-posts li a:hover small { + color: inherit; +} + + +/* + * Pagination + * + * Super lightweight (HTML-wise) blog pagination. `span`s are provide for when + * there are no more previous or next posts to show. + */ + +.pagination { + overflow: hidden; /* clearfix */ + margin-left: -1rem; + margin-right: -1rem; + font-family: "PT Sans", Helvetica, Arial, sans-serif; + color: #ccc; + text-align: center; +} + +/* Pagination items can be `span`s or `a`s */ +.pagination-item { + display: block; + padding: 1rem; + border: 1px solid #eee; +} +.pagination-item:first-child { + margin-bottom: -1px; +} + +/* Only provide a hover state for linked pagination items */ +a.pagination-item:hover { + background-color: #f5f5f5; +} + +@media (min-width: 30em) { + .pagination { + margin: 3rem 0; + } + .pagination-item { + float: left; + width: 50%; + } + .pagination-item:first-child { + margin-bottom: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + } + .pagination-item:last-child { + margin-left: -1px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + } +} + + +/* + * Reverse layout + * + * Flip the orientation of the page by placing the `.sidebar` and sidebar toggle + * on the right side. + */ + +.layout-reverse .sidebar { + left: auto; + right: -14rem; +} +.layout-reverse .sidebar-toggle { + left: auto; + right: 1rem; +} + +.layout-reverse #sidebar-checkbox:checked ~ .sidebar, +.layout-reverse #sidebar-checkbox:checked ~ .wrap, +.layout-reverse #sidebar-checkbox:checked ~ .sidebar-toggle { + -webkit-transform: translateX(-14rem); + -ms-transform: translateX(-14rem); + transform: translateX(-14rem); +} + + +/* + * Themes + * + * Apply custom color schemes by adding the appropriate class to the `body`. + * Based on colors from Base16: http://chriskempson.github.io/base16/#default. + */ + +/* Red */ +.theme-base-08 .sidebar, +.theme-base-08 .sidebar-toggle:active, +.theme-base-08 #sidebar-checkbox:checked ~ .sidebar-toggle { + background-color: #ac4142; +} +.theme-base-08 .container a, +.theme-base-08 .sidebar-toggle, +.theme-base-08 .related-posts li a:hover { + color: #ac4142; +} + +/* Orange */ +.theme-base-09 .sidebar, +.theme-base-09 .sidebar-toggle:active, +.theme-base-09 #sidebar-checkbox:checked ~ .sidebar-toggle { + background-color: #d28445; +} +.theme-base-09 .container a, +.theme-base-09 .sidebar-toggle, +.theme-base-09 .related-posts li a:hover { + color: #d28445; +} + +/* Yellow */ +.theme-base-0a .sidebar, +.theme-base-0a .sidebar-toggle:active, +.theme-base-0a #sidebar-checkbox:checked ~ .sidebar-toggle { + background-color: #f4bf75; +} +.theme-base-0a .container a, +.theme-base-0a .sidebar-toggle, +.theme-base-0a .related-posts li a:hover { + color: #f4bf75; +} + +/* Green */ +.theme-base-0b .sidebar, +.theme-base-0b .sidebar-toggle:active, +.theme-base-0b #sidebar-checkbox:checked ~ .sidebar-toggle { + background-color: #90a959; +} +.theme-base-0b .container a, +.theme-base-0b .sidebar-toggle, +.theme-base-0b .related-posts li a:hover { + color: #90a959; +} + +/* Cyan */ +.theme-base-0c .sidebar, +.theme-base-0c .sidebar-toggle:active, +.theme-base-0c #sidebar-checkbox:checked ~ .sidebar-toggle { + background-color: #75b5aa; +} +.theme-base-0c .container a, +.theme-base-0c .sidebar-toggle, +.theme-base-0c .related-posts li a:hover { + color: #75b5aa; +} + +/* Blue */ +.theme-base-0d .sidebar, +.theme-base-0d .sidebar-toggle:active, +.theme-base-0d #sidebar-checkbox:checked ~ .sidebar-toggle { + background-color: #6a9fb5; +} +.theme-base-0d .container a, +.theme-base-0d .sidebar-toggle, +.theme-base-0d .related-posts li a:hover { + color: #6a9fb5; +} + +/* Magenta */ +.theme-base-0e .sidebar, +.theme-base-0e .sidebar-toggle:active, +.theme-base-0e #sidebar-checkbox:checked ~ .sidebar-toggle { + background-color: #aa759f; +} +.theme-base-0e .container a, +.theme-base-0e .sidebar-toggle, +.theme-base-0e .related-posts li a:hover { + color: #aa759f; +} + +/* Brown */ +.theme-base-0f .sidebar, +.theme-base-0f .sidebar-toggle:active, +.theme-base-0f #sidebar-checkbox:checked ~ .sidebar-toggle { + background-color: #8f5536; +} +.theme-base-0f .container a, +.theme-base-0f .sidebar-toggle, +.theme-base-0f .related-posts li a:hover { + color: #8f5536; +} + + +/* + * Overlay sidebar + * + * Make the sidebar content overlay the viewport content instead of pushing it + * aside when toggled. + */ + +.sidebar-overlay #sidebar-checkbox:checked ~ .wrap { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); +} +.sidebar-overlay #sidebar-checkbox:checked ~ .sidebar-toggle { + box-shadow: 0 0 0 .25rem #fff; +} +.sidebar-overlay #sidebar-checkbox:checked ~ .sidebar { + box-shadow: .25rem 0 .5rem rgba(0,0,0,.1); +} + +/* Only one tweak for a reverse layout */ +.layout-reverse.sidebar-overlay #sidebar-checkbox:checked ~ .sidebar { + box-shadow: -.25rem 0 .5rem rgba(0,0,0,.1); +} diff --git a/css/syntax.css b/css/syntax.css new file mode 100644 index 0000000..6ba878e --- /dev/null +++ b/css/syntax.css @@ -0,0 +1,62 @@ +a.sourceLine { display: inline-block; line-height: 1.25; } +.container .sourceCode a.sourceLine { pointer-events: none; color: #313131;} +a.sourceLine:empty { height: 1.2em; } +.sourceCode { overflow: auto; } +code.sourceCode { white-space: pre; position: relative; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +code.sourceCode { white-space: pre-wrap; } +a.sourceLine { text-indent: -1em; padding-left: 1em; } +} +pre.numberSource a.sourceLine + { position: relative; left: -4em; } +pre.numberSource a.sourceLine::before + { content: attr(title); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; pointer-events: all; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + color: #aaaaaa; + } +/* pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; } */ +pre.numberSource { padding: 2rem; } */ +div.sourceCode + { } +@media screen { +a.sourceLine::before { text-decoration: underline; } +} +code span.al { color: #ff0000; font-weight: bold; } /* Alert */ +code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */ +code span.at { color: #7d9029; } /* Attribute */ +code span.bn { color: #40a070; } /* BaseN */ +code span.bu { } /* BuiltIn */ +code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */ +code span.ch { color: #4070a0; } /* Char */ +code span.cn { color: #880000; } /* Constant */ +code span.co { color: #60a0b0; font-style: italic; } /* Comment */ +code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */ +code span.do { color: #ba2121; font-style: italic; } /* Documentation */ +code span.dt { color: #902000; } /* DataType */ +code span.dv { color: #40a070; } /* DecVal */ +code span.er { color: #ff0000; font-weight: bold; } /* Error */ +code span.ex { } /* Extension */ +code span.fl { color: #40a070; } /* Float */ +code span.fu { color: #06287e; } /* Function */ +code span.im { } /* Import */ +code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */ +code span.kw { color: #007020; font-weight: bold; } /* Keyword */ +code span.op { color: #666666; } /* Operator */ +code span.ot { color: #007020; } /* Other */ +code span.pp { color: #bc7a00; } /* Preprocessor */ +code span.sc { color: #4070a0; } /* SpecialChar */ +code span.ss { color: #bb6688; } /* SpecialString */ +code span.st { color: #4070a0; } /* String */ +code span.va { color: #19177c; } /* Variable */ +code span.vs { color: #4070a0; } /* VerbatimString */ +code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */ diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..ca72fcc --- /dev/null +++ b/default.nix @@ -0,0 +1 @@ +(import ./release.nix { }).project diff --git a/error/404.rst b/error/404.rst new file mode 100644 index 0000000..d73b743 --- /dev/null +++ b/error/404.rst @@ -0,0 +1,12 @@ +--- +layout: default +title: "404: Page not found" +permalink: 404.html +--- + +404: Page not found +=================== + +Sorry, we've misplaced that URL or it's pointing to something that doesn't exist. `Head back home`_ to try finding it again. + +.. _Head back home: $site-url$ diff --git a/hakyll.patch b/hakyll.patch new file mode 100644 index 0000000..e69de29 diff --git a/images/hakyll-logo.svg b/images/hakyll-logo.svg new file mode 100644 index 0000000..0408c38 --- /dev/null +++ b/images/hakyll-logo.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/images/haskell-logo.png b/images/haskell-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..97c0937482e1c82c0e2a778f3ab3c4db99edcc4f GIT binary patch literal 5674 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 IGWYuDe^AuAqW}N^ literal 0 HcmV?d00001 diff --git a/index.rst b/index.rst new file mode 100644 index 0000000..62763e9 --- /dev/null +++ b/index.rst @@ -0,0 +1,5 @@ +--- +title: JFDI Collective +--- + +Welcome. We just do things. diff --git a/jfdic-web.cabal b/jfdic-web.cabal new file mode 100644 index 0000000..2b3950e --- /dev/null +++ b/jfdic-web.cabal @@ -0,0 +1,14 @@ +name: jfdic-web +version: 0.1.0.0 +build-type: Simple +cabal-version: >= 1.10 + +executable site + main-is: site.hs + build-depends: base == 4.* + , hakyll == 4.14.* + , containers == 0.6.* + , filepath == 1.4.* + , pandoc + ghc-options: -threaded + default-language: Haskell2010 diff --git a/jfdic-web.nix b/jfdic-web.nix new file mode 100644 index 0000000..ec5fd02 --- /dev/null +++ b/jfdic-web.nix @@ -0,0 +1,11 @@ +{ mkDerivation, base, hakyll, stdenv }: +mkDerivation { + pname = "jfdic-web"; + version = "0.1.0.0"; + src = ./.; + isLibrary = false; + isExecutable = true; + executableHaskellDepends = [ base hakyll ]; + license = "unknown"; + hydraPlatforms = stdenv.lib.platforms.none; +} diff --git a/js/script.js b/js/script.js new file mode 100644 index 0000000..b47910a --- /dev/null +++ b/js/script.js @@ -0,0 +1,15 @@ +(function(document) { + var toggle = document.querySelector('.sidebar-toggle'); + var sidebar = document.querySelector('#sidebar'); + var checkbox = document.querySelector('#sidebar-checkbox'); + + document.addEventListener('click', function(e) { + var target = e.target; + + if(!checkbox.checked || + sidebar.contains(target) || + (target === checkbox || target === toggle)) return; + + checkbox.checked = false; + }, false); +})(document); diff --git a/nix/sources.json b/nix/sources.json new file mode 100644 index 0000000..b0b9f35 --- /dev/null +++ b/nix/sources.json @@ -0,0 +1,26 @@ +{ + "niv": { + "branch": "master", + "description": "Easy dependency management for Nix projects", + "homepage": "https://github.com/nmattia/niv", + "owner": "nmattia", + "repo": "niv", + "rev": "dd13098d01eaa6be68237e7e38f96782b0480755", + "sha256": "1cfjdbsn0219fjzam1k7nqzkz8fb1ypab50rhyj026qbklqq2kvq", + "type": "tarball", + "url": "https://github.com/nmattia/niv/archive/dd13098d01eaa6be68237e7e38f96782b0480755.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "nixpkgs": { + "branch": "nixpkgs-unstable", + "description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to", + "homepage": "https://github.com/NixOS/nixpkgs", + "owner": "NixOS", + "repo": "nixpkgs-channels", + "rev": "10100a97c8964e82b30f180fda41ade8e6f69e41", + "sha256": "011f36kr3c1ria7rag7px26bh73d1b0xpqadd149bysf4hg17rln", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs-channels/archive/10100a97c8964e82b30f180fda41ade8e6f69e41.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + } +} diff --git a/nix/sources.nix b/nix/sources.nix new file mode 100644 index 0000000..8a725cb --- /dev/null +++ b/nix/sources.nix @@ -0,0 +1,134 @@ +# This file has been generated by Niv. + +let + + # + # The fetchers. fetch_ fetches specs of type . + # + + fetch_file = pkgs: spec: + if spec.builtin or true then + builtins_fetchurl { inherit (spec) url sha256; } + else + pkgs.fetchurl { inherit (spec) url sha256; }; + + fetch_tarball = pkgs: spec: + if spec.builtin or true then + builtins_fetchTarball { inherit (spec) url sha256; } + else + pkgs.fetchzip { inherit (spec) url sha256; }; + + fetch_git = spec: + builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; }; + + fetch_builtin-tarball = spec: + builtins.trace + '' + WARNING: + The niv type "builtin-tarball" will soon be deprecated. You should + instead use `builtin = true`. + + $ niv modify -a type=tarball -a builtin=true + '' + builtins_fetchTarball { inherit (spec) url sha256; }; + + fetch_builtin-url = spec: + builtins.trace + '' + WARNING: + The niv type "builtin-url" will soon be deprecated. You should + instead use `builtin = true`. + + $ niv modify -a type=file -a builtin=true + '' + (builtins_fetchurl { inherit (spec) url sha256; }); + + # + # Various helpers + # + + # The set of packages used when specs are fetched using non-builtins. + mkPkgs = sources: + let + sourcesNixpkgs = + import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {}; + hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; + hasThisAsNixpkgsPath = == ./.; + in + if builtins.hasAttr "nixpkgs" sources + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import {} + else + abort + '' + Please specify either (through -I or NIX_PATH=nixpkgs=...) or + add a package called "nixpkgs" to your sources.json. + ''; + + # The actual fetching function. + fetch = pkgs: name: spec: + + if ! builtins.hasAttr "type" spec then + abort "ERROR: niv spec ${name} does not have a 'type' attribute" + else if spec.type == "file" then fetch_file pkgs spec + else if spec.type == "tarball" then fetch_tarball pkgs spec + else if spec.type == "git" then fetch_git spec + else if spec.type == "builtin-tarball" then fetch_builtin-tarball spec + else if spec.type == "builtin-url" then fetch_builtin-url spec + else + abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; + + # Ports of functions for older nix versions + + # a Nix version of mapAttrs if the built-in doesn't exist + mapAttrs = builtins.mapAttrs or ( + f: set: with builtins; + listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) + ); + + # fetchTarball version that is compatible between all the versions of Nix + builtins_fetchTarball = { url, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchTarball; + in + if lessThan nixVersion "1.12" then + fetchTarball { inherit url; } + else + fetchTarball attrs; + + # fetchurl version that is compatible between all the versions of Nix + builtins_fetchurl = { url, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchurl; + in + if lessThan nixVersion "1.12" then + fetchurl { inherit url; } + else + fetchurl attrs; + + # Create the final "sources" from the config + mkSources = config: + mapAttrs ( + name: spec: + if builtins.hasAttr "outPath" spec + then abort + "The values in sources.json should not have an 'outPath' attribute" + else + spec // { outPath = fetch config.pkgs name spec; } + ) config.sources; + + # The "config" used by the fetchers + mkConfig = + { sourcesFile ? ./sources.json + , sources ? builtins.fromJSON (builtins.readFile sourcesFile) + , pkgs ? mkPkgs sources + }: rec { + # The sources, i.e. the attribute set of spec name to spec + inherit sources; + + # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers + inherit pkgs; + }; +in +mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/pages/About.rst b/pages/About.rst new file mode 100644 index 0000000..32497b8 --- /dev/null +++ b/pages/About.rst @@ -0,0 +1,7 @@ +--- +title: About +--- + +We're the spiritual successor to `C@T`_. + +.. _C@T:: https://web.archive.org/web/20070102063147/http://cat.org.au/ diff --git a/pages/Contact.rst b/pages/Contact.rst new file mode 100644 index 0000000..b0edf07 --- /dev/null +++ b/pages/Contact.rst @@ -0,0 +1,5 @@ +--- +title: Contact +--- + +You can contact the JFDI collective via our Matrix room. diff --git a/posts/2015-08-12-spqr.markdown b/posts/2015-08-12-spqr.markdown new file mode 100644 index 0000000..b147fcd --- /dev/null +++ b/posts/2015-08-12-spqr.markdown @@ -0,0 +1,60 @@ +--- +title: S.P.Q.R. +tags: Mauris, lorem +--- + +Mauris in lorem nisl. Maecenas tempus facilisis ante, eget viverra nisl +tincidunt et. Donec turpis lectus, mattis ac malesuada a, accumsan eu libero. +Morbi condimentum, tortor et tincidunt ullamcorper, sem quam pretium nulla, id +convallis lectus libero nec turpis. Proin dapibus nisi id est sodales nec +ultrices tortor pellentesque. Vivamus vel nisi ac lacus sollicitudin vulputate +ac ut ligula. Nullam feugiat risus eget eros gravida in molestie sapien euismod. +Nunc sed hendrerit orci. Nulla mollis consequat lorem ac blandit. Ut et turpis +mauris. Nulla est odio, posuere id ullamcorper sit amet, tincidunt vel justo. +Curabitur placerat tincidunt varius. Nulla vulputate, ipsum eu consectetur +mollis, dui nibh aliquam neque, at ultricies leo ligula et arcu. Proin et mi +eget tellus sodales lobortis. Sed tempor, urna vel pulvinar faucibus, lectus +urna vehicula ante, at facilisis dolor odio at lorem. Morbi vehicula euismod +urna, et imperdiet urna ornare vitae. + +Sed tincidunt sollicitudin ultrices. In hac habitasse platea dictumst. Morbi +ligula lectus, egestas at ultricies nec, fringilla et tellus. Duis urna lorem, +bibendum a ornare sed, euismod sed nunc. Aliquam tempor massa at velit fringilla +fringilla. Praesent sit amet tempor felis. Maecenas id felis ac velit aliquam +tempor a sit amet orci. Nunc placerat nulla pellentesque sem commodo cursus. +Praesent quis sapien orci, quis ultricies augue. Nam vestibulum sem non augue +semper tincidunt pellentesque ipsum volutpat. Duis congue, nunc a aliquam +luctus, quam ante convallis nisi, ac pellentesque lacus orci vel turpis. Cum +sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus +mus. Suspendisse hendrerit nisl eu felis sagittis faucibus. Nunc eu congue +lorem. Quisque non nibh nisi, et ultrices massa. Sed vitae erat vitae nulla +pellentesque fermentum. + +Ut diam nunc, consectetur ut ultrices eu, iaculis sed felis. Sed lacinia, odio +et accumsan luctus, arcu ipsum accumsan erat, sit amet malesuada libero lacus et +velit. Donec accumsan tristique tristique. Proin a metus magna, vitae mattis +nisl. Integer a libero ipsum. Mauris faucibus eleifend metus id sodales. Morbi +ornare, nibh nec facilisis imperdiet, turpis sem commodo lorem, id commodo +mauris metus vitae justo. Etiam at pellentesque tortor. Proin mollis accumsan +ligula, nec tempus augue auctor quis. Nulla lacinia, mi quis lobortis auctor, +nisi diam posuere dui, pulvinar feugiat dui libero eget quam. Fusce eu risus +nunc, a consectetur orci. Class aptent taciti sociosqu ad litora torquent per +conubia nostra, per inceptos himenaeos. Maecenas venenatis aliquet orci, a +ultricies sem facilisis eu. Donec dolor purus, porta condimentum convallis nec, +dignissim nec libero. + +Etiam rutrum ultricies dui, et interdum metus elementum et. Nulla sapien nunc, +interdum tristique porttitor in, laoreet vitae mi. Ut vehicula auctor mauris sit +amet bibendum. Phasellus adipiscing mattis libero, eget adipiscing erat +dignissim at. Vivamus convallis malesuada metus nec cursus. Ut cursus, lorem +eleifend sollicitudin condimentum, felis tortor sodales augue, ac tempus lacus +ipsum vitae quam. Vestibulum vitae lacus non tortor vehicula iaculis faucibus +quis massa. + +Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus +mus. Duis malesuada neque nec ante porttitor accumsan. Suspendisse potenti. +Aliquam in lacus magna, imperdiet laoreet lectus. Praesent id diam nec ante +commodo rhoncus nec vel augue. Pellentesque tortor massa, dignissim ut sagittis +sed, hendrerit vitae nunc. Nam gravida, urna vitae hendrerit rutrum, felis augue +vulputate tortor, ut varius velit libero nec lectus. In adipiscing massa in est +scelerisque ullamcorper. Vivamus in nisi metus. diff --git a/posts/2015-10-07-rosa-rosa-rosam.markdown b/posts/2015-10-07-rosa-rosa-rosam.markdown new file mode 100644 index 0000000..8cfaaca --- /dev/null +++ b/posts/2015-10-07-rosa-rosa-rosam.markdown @@ -0,0 +1,47 @@ +--- +title: Rosa Rosa Rosam +author: Ovidius +tags: lorem +--- + +Suspendisse pharetra ullamcorper sem et auctor. Suspendisse vitae tellus eu +turpis dignissim gravida ut ut tortor. Cum sociis natoque penatibus et magnis +dis parturient montes, nascetur ridiculus mus. Morbi aliquam sapien quis nisl +sodales non aliquet nisl iaculis. Curabitur fermentum orci vel sapien +pellentesque id condimentum metus vehicula. Curabitur turpis purus, scelerisque +at interdum quis, placerat sit amet tortor. Aliquam erat volutpat. + +Integer posuere felis non arcu suscipit ullamcorper. Nam tempus risus venenatis +orci sagittis eu aliquam ante tincidunt. Aenean vehicula ipsum id sapien +tincidunt commodo. Aliquam erat volutpat. Curabitur vehicula libero ac turpis +cursus consectetur. Praesent posuere egestas purus et dapibus. Mauris egestas, +lectus vitae scelerisque ultricies, metus lorem tempor nisi, sed vehicula tortor +mauris nec urna. Quisque urna tellus, facilisis at mollis eget, adipiscing in +nisl. Proin quam arcu, euismod et imperdiet sed, ultricies sed orci. + +Nulla malesuada sem eget lectus scelerisque nec rhoncus metus interdum. In dui +felis, rhoncus id scelerisque eget, vulputate id sem. Nulla facilisi. Vestibulum +eleifend, metus dignissim lacinia ornare, magna nulla vehicula nisi, sed +molestie mauris ipsum vel turpis. Class aptent taciti sociosqu ad litora +torquent per conubia nostra, per inceptos himenaeos. Nulla urna leo, vehicula +eget dignissim a, hendrerit ut risus. Fusce ultricies elementum placerat. Nam at +dolor sed nisi mollis sollicitudin vitae at urna. Vestibulum iaculis adipiscing +eros et mollis. + +Phasellus ultricies elit eu risus sagittis eu dictum ante ultrices. Nulla +congue, augue ac placerat tempor, orci mi luctus nisi, at varius ipsum sem sed +eros. Vivamus eget velit eget felis posuere ornare. In sed metus non est iaculis +facilisis dapibus sit amet enim. Aliquam viverra tortor eget neque volutpat in +auctor urna rutrum. Aliquam ligula augue, congue sit amet rutrum in, semper vel +nulla. Sed tempus porttitor faucibus. Donec cursus sodales nulla, quis lacinia +mi vehicula vel. Sed nec purus orci. Nam leo sapien, rutrum a ultrices quis, +placerat vel ligula. Donec massa quam, pellentesque et molestie nec, hendrerit +id mauris. In hac habitasse platea dictumst. Cras quis quam sem. Curabitur in +arcu diam, in interdum mauris. + +Proin lorem sapien, iaculis et faucibus nec, dictum sed nunc. Pellentesque in +purus justo. Vestibulum facilisis rutrum nisi, a egestas nunc suscipit sed. Ut +quis tortor a arcu bibendum placerat non sed ante. Praesent orci sem, posuere +sit amet cursus molestie, volutpat ut purus. Curabitur aliquam, purus in +pharetra viverra, lorem leo aliquam tellus, vel consequat felis neque et mauris. +Aliquam erat volutpat. diff --git a/posts/2015-11-28-carpe-diem.markdown b/posts/2015-11-28-carpe-diem.markdown new file mode 100644 index 0000000..fcdf7a2 --- /dev/null +++ b/posts/2015-11-28-carpe-diem.markdown @@ -0,0 +1,51 @@ +--- +title: Carpe Diem +tags: lorem, quam +--- + +Fusce tortor quam, egestas in posuere quis, porttitor vel turpis. Donec +vulputate porttitor augue at rhoncus. Proin iaculis consectetur sagittis. +Curabitur venenatis turpis sit amet purus tristique nec posuere risus laoreet. +Nullam nisi sem, dapibus id semper id, egestas vel arcu. Morbi porttitor ipsum +placerat erat consequat sed consequat purus feugiat. Donec auctor elit ut risus +mattis facilisis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +Proin vulputate sapien facilisis leo ornare pulvinar. Fusce tempus massa a risus +semper iaculis. Suspendisse sollicitudin posuere nunc, sit amet rutrum leo +facilisis mattis. Sed ornare auctor dui, vitae rutrum neque auctor sit amet. +Proin ac dui magna. Mauris vehicula interdum augue, nec ultrices libero egestas +quis. Nunc convallis euismod ipsum, id sollicitudin orci consequat ac. Fusce +bibendum congue libero, in rutrum nulla congue non. Cras sit amet risus tortor, +eu pellentesque dui. Phasellus euismod enim non nibh sodales quis consectetur +lorem laoreet. Vivamus a egestas quam. Curabitur in tortor augue, vitae varius +tellus. Integer varius, elit ac gravida suscipit, eros erat pellentesque nisi, +et tristique augue odio id nulla. Aliquam sit amet nunc vel tellus hendrerit +tempus ac vel sem. + +Aenean tincidunt sollicitudin sapien ut porttitor. Curabitur molestie adipiscing +lorem vel scelerisque. Donec vitae interdum est. Proin rutrum vulputate +faucibus. Suspendisse sit amet felis odio, non volutpat ante. Sed eu lectus +quam. Curabitur tristique rhoncus est, vel commodo tortor suscipit semper. +Maecenas feugiat vestibulum nisi id facilisis. Nulla non tincidunt libero. +Praesent ultrices interdum commodo. Sed euismod nisl auctor leo ultrices rutrum. +Aliquam nibh felis, congue molestie blandit at, bibendum at eros. Aenean +tincidunt, tortor iaculis placerat sollicitudin, lorem justo tempor diam, et +posuere sapien leo et magna. Quisque vel aliquam mauris. + +Proin varius tempus fermentum. Cum sociis natoque penatibus et magnis dis +parturient montes, nascetur ridiculus mus. Sed tincidunt nunc id magna +adipiscing non sollicitudin turpis tempor. Etiam vel elit ipsum, quis euismod +velit. Quisque elementum magna vitae quam venenatis lacinia. Sed at arcu ipsum. +Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos +himenaeos. Donec ut lorem ac sapien cursus lacinia sit amet mollis dolor. +Vivamus tempus odio nec magna faucibus sed hendrerit lorem tempor. + +Vestibulum eu nisi arcu. Curabitur nisi risus, fermentum ut lacinia ut, interdum +nec magna. Nunc aliquet gravida massa, eu aliquam lorem faucibus at. Sed +sollicitudin volutpat velit id tempor. In nibh justo, pharetra et pretium +dignissim, tempus in turpis. Phasellus eget lobortis nisl. Phasellus sed +fermentum diam. Nam tempus pharetra odio, quis congue eros imperdiet eu. Aliquam +dui eros, hendrerit et vulputate vel, porta eu eros. Nullam nisi dui, commodo +eget pharetra ut, ornare sit amet nunc. Fusce vel neque urna. Maecenas nulla +ante, egestas at consequat quis, fermentum a enim. Aliquam id tristique urna. +Integer augue justo, scelerisque et consectetur id, rhoncus eget enim. diff --git a/posts/2015-12-07-tu-quoque.markdown b/posts/2015-12-07-tu-quoque.markdown new file mode 100644 index 0000000..c547d81 --- /dev/null +++ b/posts/2015-12-07-tu-quoque.markdown @@ -0,0 +1,59 @@ +--- +title: Tu Quoque +author: Julius +tags: lorem, quam +--- + +Vestibulum leo turpis, dignissim quis ultrices sit amet, iaculis ac ligula. +Pellentesque tristique, velit eget scelerisque scelerisque, est dolor ultrices +arcu, quis ullamcorper justo arcu luctus mauris. Integer congue molestie nisi id +posuere. Fusce pellentesque gravida tempus. Integer viverra tortor nec eros +mollis quis convallis sem laoreet. Nulla id libero ac erat varius laoreet. Proin +sed est est. Curabitur lacinia fermentum lorem, elementum malesuada ipsum +malesuada ut. Donec suscipit elit id leo vehicula mattis non sed leo. Morbi +varius eleifend varius. Nulla vestibulum, neque vitae aliquam eleifend, nisi +tellus placerat nunc, quis suscipit elit turpis eu tortor. Etiam euismod +convallis lectus quis venenatis. Phasellus laoreet magna in nibh cursus eu +egestas nulla convallis. Aliquam vel ullamcorper risus. Fusce dictum, massa id +consequat viverra, nulla ante tristique est, a faucibus nisi enim nec dui. Donec +metus ligula, condimentum at porttitor eget, lobortis at quam. + +Aenean vel libero in magna ultricies congue in a odio. Donec faucibus rutrum +ornare. Fusce dictum eleifend fermentum. Vestibulum vel nibh a metus porttitor +rhoncus. Pellentesque id quam neque, eget molestie arcu. Integer in elit vel +neque viverra ultricies in eget massa. Nam ut convallis est. Pellentesque eros +eros, sodales non vehicula et, tincidunt ut odio. Cras suscipit ultrices metus +sit amet molestie. Fusce enim leo, vehicula sed sodales quis, adipiscing at +ipsum. + +Nunc tempor dignissim enim, sed tincidunt eros bibendum quis. Curabitur et dolor +augue, id laoreet mi. Nulla cursus felis id dui vehicula vitae ornare lorem +blandit. Cras eget dui nec odio volutpat pharetra. Fusce hendrerit justo justo, +vel imperdiet enim. Vivamus elit risus, interdum ultrices accumsan eleifend, +vestibulum vitae sapien. Integer bibendum ullamcorper tristique. Nulla quis odio +lectus, quis eleifend augue. Integer a ligula mauris. Aenean et tempus tortor. +Quisque at tortor mi. Vivamus accumsan feugiat est a blandit. Sed vitae enim ut +dolor semper sodales. Duis tristique, ante et placerat elementum, nulla tellus +pellentesque sapien, quis posuere velit mi eget nulla. Sed vestibulum nunc non +est porttitor ut rutrum nibh semper. Pellentesque habitant morbi tristique +senectus et netus et malesuada fames ac turpis egestas. + +Nulla adipiscing ultricies lobortis. Vivamus iaculis nisl vitae tellus laoreet +vitae aliquet lacus mollis. Phasellus ut lacus urna, sed sagittis ante. Etiam +consectetur pretium nisl sed dignissim. Pellentesque convallis, nisl eget +commodo mollis, sem magna consequat arcu, sed pretium ipsum arcu sit amet neque. +Aliquam erat volutpat. Morbi sed mi sed urna vestibulum placerat vitae vel +metus. Fusce ac ante at justo pharetra vehicula. Vivamus vel tortor eget augue +aliquet aliquet at vel odio. Nunc venenatis, magna quis facilisis fringilla, +augue tellus varius neque, in vulputate est eros ut tortor. Duis lorem neque, +aliquam congue posuere id, condimentum non dui. Phasellus ut dui massa, +porttitor suscipit augue. Praesent quis tellus quam, vel volutpat metus. Vivamus +enim est, aliquam in imperdiet et, sagittis eu ligula. Vestibulum hendrerit +placerat orci et aliquet. Cras pharetra, dolor placerat lobortis tempor, metus +odio cursus ligula, et posuere lacus ligula quis dui. + +Donec a lectus eu nibh malesuada aliquam. Proin at metus quam, et tincidunt leo. +Quisque lacus justo, scelerisque sodales pulvinar sed, dignissim ut sapien. +Vivamus diam felis, adipiscing sollicitudin ultricies id, accumsan ac felis. In +eu posuere ligula. Suspendisse potenti. Donec porttitor dictum dui id vehicula. +Integer ante velit, congue id dictum et, adipiscing a tortor. diff --git a/release.nix b/release.nix new file mode 100644 index 0000000..16a893f --- /dev/null +++ b/release.nix @@ -0,0 +1,46 @@ +let + sources = import ./nix/sources.nix; +in +{ compiler ? "ghc883" +, pkgs ? import sources.nixpkgs { } +}: + +let + inherit (pkgs.lib.trivial) flip pipe; + inherit (pkgs.haskell.lib) appendPatch appendConfigureFlags; + + haskellPackages = pkgs.haskell.packages.${compiler}.override { + overrides = hpNew: hpOld: { + hakyll = + pipe + hpOld.hakyll + [ (flip appendPatch ./hakyll.patch) + (flip appendConfigureFlags [ "-f" "watchServer" "-f" "previewServer" ]) + ]; + + resrok-web = hpNew.callCabal2nix "resrok-web" ./. { }; + + niv = import sources.niv { }; + }; + }; + + project = haskellPackages.resrok-web; +in +{ + project = project; + + shell = haskellPackages.shellFor { + packages = p: with p; [ + project + ]; + #buildInputs = with haskellPackages; [ + # ghcid + # hlint # or ormolu + # niv + # pkgs.cacert # needed for niv + # pkgs.nix # needed for niv + # zlib + #]; + withHoogle = true; + }; +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..bc6afd2 --- /dev/null +++ b/shell.nix @@ -0,0 +1 @@ +(import ./release.nix { }).shell diff --git a/site.hs b/site.hs new file mode 100644 index 0000000..a02ea19 --- /dev/null +++ b/site.hs @@ -0,0 +1,198 @@ +-------------------------------------------------------------------------------- +{-# LANGUAGE OverloadedStrings #-} +import Data.Monoid (mappend) +import Data.List (sortBy) +import Data.Ord (comparing) +import Hakyll +import Control.Monad (liftM, forM_) +import System.FilePath (takeBaseName) + +-------------------------------------------------------------------------------- +main :: IO () +main = hakyll $ do + match ("images/*" .||. "js/*") $ do + route idRoute + compile copyFileCompiler + + match "css/*" $ do + route idRoute + compile compressCssCompiler + + match "error/*" $ do + route $ (gsubRoute "error/" (const "") `composeRoutes` setExtension "html") + compile $ pandocCompiler + >>= applyAsTemplate siteCtx + >>= loadAndApplyTemplate "templates/default.html" (baseSidebarCtx <> siteCtx) + + match "pages/*" $ do + route $ setExtension "html" + compile $ do + pageName <- takeBaseName . toFilePath <$> getUnderlying + let pageCtx = constField pageName "" `mappend` + baseNodeCtx + let evalCtx = functionField "get-meta" getMetadataKey `mappend` + functionField "eval" (evalCtxKey pageCtx) + let activeSidebarCtx = sidebarCtx (evalCtx <> pageCtx) + + pandocCompiler + >>= saveSnapshot "page-content" + >>= loadAndApplyTemplate "templates/page.html" siteCtx + >>= loadAndApplyTemplate "templates/default.html" (activeSidebarCtx <> siteCtx) + >>= relativizeUrls + + tags <- buildTags "posts/*" (fromCapture "tags/*.html") + + match "posts/*" $ version "meta" $ do + route $ setExtension "html" + compile getResourceBody + + match "posts/*" $ do + route $ setExtension "html" + compile $ do + posts <- loadAll ("posts/*" .&&. hasVersion "meta") + let taggedPostCtx = (tagsField "tags" tags) `mappend` + postCtx `mappend` + (relatedPostsCtx posts 3) + + pandocCompiler + >>= saveSnapshot "content" + >>= loadAndApplyTemplate "templates/post.html" taggedPostCtx + >>= loadAndApplyTemplate "templates/default.html" (baseSidebarCtx <> siteCtx) + >>= relativizeUrls + + create ["archive.html"] $ do + route idRoute + compile $ do + posts <- recentFirst =<< loadAllSnapshots ("posts/*" .&&. hasNoVersion) "content" + let archiveCtx = + listField "posts" postCtx (return posts) `mappend` + constField "title" "Archive" `mappend` + constField "archive" "" `mappend` + siteCtx + + makeItem "" + >>= loadAndApplyTemplate "templates/archive.html" archiveCtx + >>= loadAndApplyTemplate "templates/default.html" (baseSidebarCtx <> archiveCtx) + >>= relativizeUrls + + paginate <- buildPaginateWith postsGrouper "posts/*" postsPageId + + paginateRules paginate $ \page pattern -> do + route idRoute + compile $ do + posts <- recentFirst =<< loadAllSnapshots (pattern .&&. hasNoVersion) "content" + let indexCtx = + constField "title" (if page == 1 then "Home" + else "Blog posts, page " ++ show page) `mappend` + listField "posts" postCtx (return posts) `mappend` + constField "home" "" `mappend` + paginateContext paginate page `mappend` + siteCtx + + makeItem "" + >>= applyAsTemplate indexCtx + >>= loadAndApplyTemplate "templates/index.html" indexCtx + >>= loadAndApplyTemplate "templates/default.html" (baseSidebarCtx <> indexCtx) + >>= relativizeUrls + + match "templates/*" $ compile templateBodyCompiler + + create ["atom.xml"] $ do + route idRoute + compile $ do + let feedCtx = postCtx `mappend` + bodyField "description" + posts <- fmap (take 10) . recentFirst =<< loadAllSnapshots ("posts/*" .&&. hasNoVersion) "content" + renderAtom feedConfig feedCtx posts + +-------------------------------------------------------------------------------- + +postsGrouper :: MonadFail m => MonadMetadata m => [Identifier] -> m [[Identifier]] +postsGrouper = liftM (paginateEvery 3) . sortRecentFirst + + +postsPageId :: PageNumber -> Identifier +postsPageId n = fromFilePath $ if (n == 1) then "index.html" else show n ++ "/index.html" + +-------------------------------------------------------------------------------- + +feedConfig :: FeedConfiguration +feedConfig = FeedConfiguration + { feedTitle = "Resilient Rockhampton" + , feedDescription = "All We Have Is Each Other" + , feedAuthorName = "Resilient Rockhampton" + , feedAuthorEmail = "collective@resrok.org" + , feedRoot = "https://resrok.org" + } + +-------------------------------------------------------------------------------- + +siteCtx :: Context String +siteCtx = + baseCtx `mappend` + constField "site_description" "Resilient Rockhampton" `mappend` + constField "site-url" "https://resrok.org" `mappend` + constField "tagline" "All We Have Is Each Other" `mappend` + constField "site-title" "Resilient Rockhampton" `mappend` + constField "copy-year" "2021" `mappend` + constField "github-repo" "https://source.resrok.org/resrok/resrok-web" `mappend` + defaultContext + +baseCtx = + constField "baseurl" "http://localhost:8000" + +-------------------------------------------------------------------------------- + +postCtx :: Context String +postCtx = + dateField "date" "%B %e, %Y" `mappend` + defaultContext + +tagsRulesVersioned tags rules = + forM_ (tagsMap tags) $ \(tag, identifiers) -> + rulesExtraDependencies [tagsDependency tags] $ + create [tagsMakeId tags tag] $ + rules tag identifiers + +relatedPostsCtx + :: [Item String] -> Int -> Context String +relatedPostsCtx posts n = listFieldWith "related_posts" postCtx selectPosts + where + rateItem ts i = length . filter (`elem` ts) <$> (getTags $ itemIdentifier i) + selectPosts s = do + postTags <- getTags $ itemIdentifier s + let trimmedItems = filter (not . matchPath s) posts + take n . reverse <$> sortOnM (rateItem postTags) trimmedItems + +matchPath :: Item String -> Item String -> Bool +matchPath x y = eqOn (toFilePath . itemIdentifier) x y + +eqOn :: Eq b => (a -> b) -> a -> a -> Bool +eqOn f x y = f x == f y + +sortOnM :: (Monad m, Ord b) => (a -> m b) -> [a] -> m [a] +sortOnM f xs = map fst . sortBy (comparing snd) . zip xs <$> mapM f xs + +-------------------------------------------------------------------------------- + +sidebarCtx :: Context String -> Context String +sidebarCtx nodeCtx = + listField "list_pages" nodeCtx (loadAllSnapshots ("pages/*" .&&. hasNoVersion) "page-content") `mappend` + defaultContext + +baseNodeCtx :: Context String +baseNodeCtx = + urlField "node-url" `mappend` + titleField "title" `mappend` + baseCtx + +baseSidebarCtx = sidebarCtx baseNodeCtx + +evalCtxKey :: Context String -> [String] -> Item String -> Compiler String +evalCtxKey context [key] item = (unContext context key [] item) >>= \cf -> + case cf of + StringField s -> return s + _ -> error $ "Internal error: StringField expected" + +getMetadataKey :: [String] -> Item String -> Compiler String +getMetadataKey [key] item = getMetadataField' (itemIdentifier item) key diff --git a/templates/archive.html b/templates/archive.html new file mode 100644 index 0000000..8a4c8d7 --- /dev/null +++ b/templates/archive.html @@ -0,0 +1,4 @@ +

+ Here you can find all our previous posts: + $partial("templates/post-list.html")$ +
diff --git a/templates/default.html b/templates/default.html new file mode 100644 index 0000000..c3c7d05 --- /dev/null +++ b/templates/default.html @@ -0,0 +1,33 @@ + + + + $partial("templates/head.html")$ + + + + $partial("templates/sidebar.html")$ + + +
+
+
+

+ $site-title$ + $tagline$ +

+
+
+ +
+ $body$ +
+
+ + + + + + + + diff --git a/templates/head.html b/templates/head.html new file mode 100644 index 0000000..0945e9a --- /dev/null +++ b/templates/head.html @@ -0,0 +1,35 @@ + + + + + + + + $if(home)$ + $site-title$ · $tagline$ + $else$ + $title$ · $site-title$ + $endif$ + + + $if(url)$ + $if(baseurl)$ + + $endif$ + $endif$ + + + + + + + + + + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..b3758fa --- /dev/null +++ b/templates/index.html @@ -0,0 +1,31 @@ +
+ $for(posts)$ +
+

+ + $title$ + +

+ + + $body$ +
+ $endfor$ +
+ + diff --git a/templates/page.html b/templates/page.html new file mode 100644 index 0000000..2d29904 --- /dev/null +++ b/templates/page.html @@ -0,0 +1,4 @@ +
+

$title$

+ $body$ +
diff --git a/templates/post-list.html b/templates/post-list.html new file mode 100644 index 0000000..71cf1b9 --- /dev/null +++ b/templates/post-list.html @@ -0,0 +1,7 @@ + diff --git a/templates/post.html b/templates/post.html new file mode 100644 index 0000000..486b461 --- /dev/null +++ b/templates/post.html @@ -0,0 +1,31 @@ +
+

+ + $title$ + +

+ + $body$ +
+ +$if(related_posts)$ + +$endif$ diff --git a/templates/sidebar.html b/templates/sidebar.html new file mode 100644 index 0000000..76fc48f --- /dev/null +++ b/templates/sidebar.html @@ -0,0 +1,38 @@ + + + + +