commit 321ac6c77d870a54fcf901423bdc2280bbcac755 Author: Raging Raspberries Date: Thu Nov 4 19:46:37 2021 +1000 Initial commit 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 0000000..97c0937 Binary files /dev/null and b/images/haskell-logo.png differ 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 @@ + + + + +