commit 3b41eef57dfe9fbb4892acb5fc954b84606fd104 Author: Youwen Wu <38934577+couscousdude@users.noreply.github.com> Date: Wed May 22 22:17:41 2024 -0700 Initial commit diff --git a/.ghci b/.ghci new file mode 100644 index 0000000..a0b188d --- /dev/null +++ b/.ghci @@ -0,0 +1,7 @@ +:def hoogle \x -> return $ ":!hoogle --count=15 \"" ++ x ++ "\"" +:def doc \x -> return $ ":!hoogle --info \"" ++ x ++ "\"" +:set -Wall +:set -fno-warn-type-defaults -ferror-spans -freverse-errors -fprint-expanded-synonyms +:set prompt "\ESC[0;32m%s\n\ESC[m[ghci]\ESC[38;5;172mλ \ESC[m\STX" +:set prompt-cont " \ESC[38;5;172m> \ESC[m" +:load ssg/src/Main.hs diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..ba79d38 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: rpearce diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..1f97b0b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + time: '00:00' + timezone: UTC + open-pull-requests-limit: 10 + commit-message: + prefix: "chore" + include: "scope" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..bb01806 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,58 @@ +name: CI + +on: + pull_request: + push: + +jobs: + build-nix: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Nix + uses: cachix/install-nix-action@V27 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + allow-import-from-derivation = true + auto-optimise-store = true + experimental-features = nix-command flakes + substituters = https://cache.nixos.org https://cache.iog.io + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= + + - name: Build with cachix + uses: cachix/cachix-action@v15 + with: + name: hakyll-nix-template + authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} + + - run: nix build --accept-flake-config + + - name: Artifact pages + uses: actions/upload-artifact@v4 + with: + name: pages + path: result/dist + + deploy: + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + needs: [build-nix] + + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: pages + path: result + + - name: Deploy to GitHub Pages + if: success() + uses: crazy-max/ghaction-github-pages@v4.0.0 + with: + build_dir: result + target_branch: gh-pages + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed60dba --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +!src/js/dist +.DS_Store +.ghc.environment.* +_cache +_tmp +dist +dist-newstyle +node_modules +result diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1009f96 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2020, Robert Pearce +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ae1768b --- /dev/null +++ b/README.md @@ -0,0 +1,108 @@ +# hakyll-nix-template + +[Hakyll](https://jaspervdj.be/hakyll/) + [Nix](https://nixos.org) template + +## Quick tips + +* Read the tutorial to get started! https://robertwpearce.com/the-hakyll-nix-template-tutorial.html +* If you make changes to anything inside of `ssg/`, you'll need to clean the + hakyll cache and rebuild. This is the preferred series of commands for + rebuilding (with logs), cleaning the cache, and re-running the dev server: + + ```default + nix build --print-build-logs && \ + nix run . clean && \ + nix run . watch + ``` + +## Features + +* Build your site into the `./result/dist` folder: + ``` + λ nix build + ``` +* Start hakyll's dev server that reloads when changes are made: + ``` + λ nix run . watch + Listening on http://127.0.0.1:8000 + ...more logs + ``` +* Run any hakyll command through `nix run .`! + ``` + λ nix run . clean + Removing dist... + Removing ssg/_cache... + Removing ssg/_tmp... + ``` +* Start a development environment that + * has your shell environment + * has `hakyll-site` (for building/watching/cleaning hakyll projects) + * has `hakyll-init` (for generating new projects) + * can have anything else you put in the `shell.buildInputs` of the + `hakyllProject` in `flake.nix` + * is set up to run `ghci` with some defaults and the modules loaded so you can + make your own changes and test them out in the ghci REPL + + ``` + λ nix develop + + [hakyll-nix]λ hakyll-site build + ... + Success + + [hakyll-nix]λ ghci + ... + [1 of 1] Compiling Main ( ssg/src/Main.hs, interpreted ) + ... + + λ > + ``` + +### hakyll + +All of this is custmomizable, and here are some things that are already done for +you: + +* [pandoc](https://github.com/jgm/pandoc/) markdown customization to make it as + close to GitHub's markdown style as possible +* [`slugger`](https://hackage.haskell.org/package/slugger) module is included that makes nice link URIs based on post titles +* RSS & Atom XML feed generation +* Sitemap generation +* Code syntax highlighting customization +* ...other reasonable defaults + +Configure the dev server, cache & tmp directories, and more in +`./ssg/src/Main.hs`. + +### Deployment + +Deployment is set up through a [GitHub +Action](https://github.com/features/actions) with [cachix](https://cachix.org), +and it deploys to a [GitHub Pages](https://pages.github.com/) branch, +`gh-pages`, when you merge code into your main branch. + +Setup information can be found below in the "Cachix" section. + +Note: If your main branch's name isn't `main`, ensure `'refs/heads/main'` gets +updated to `'refs/heads/my-main-branch'` in `./github/workflows/main.yml`. + +## Setup + +### Nix & Flakes + +If you don't have [nix](https://nixos.org), follow [the nix installation +instructions](https://nixos.org/download.html). + +Once you have nix installed, follow the instructions here to get access to +flakes: https://nixos.wiki/wiki/Flakes. + +### Cachix + +The `./.github/workflows/main.yml` file builds with help from +[cachix](https://app.cachix.org), so you'll need to generate a signing key to be +able to do this. + +1. Create a cache on cachix for your project +1. Follow cachix's instructions to generate a signing keypair +1. Copy the signing keypair value to a new `CACHIX_SIGNING_KEY` secret on + https://github.com/settings/secrets diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..c14bce6 --- /dev/null +++ b/flake.lock @@ -0,0 +1,693 @@ +{ + "nodes": { + "HTTP": { + "flake": false, + "locked": { + "lastModified": 1451647621, + "narHash": "sha256-oHIyw3x0iKBexEo49YeUDV1k74ZtyYKGR2gNJXXRxts=", + "owner": "phadej", + "repo": "HTTP", + "rev": "9bc0996d412fef1787449d841277ef663ad9a915", + "type": "github" + }, + "original": { + "owner": "phadej", + "repo": "HTTP", + "type": "github" + } + }, + "cabal-32": { + "flake": false, + "locked": { + "lastModified": 1603716527, + "narHash": "sha256-X0TFfdD4KZpwl0Zr6x+PLxUt/VyKQfX7ylXHdmZIL+w=", + "owner": "haskell", + "repo": "cabal", + "rev": "48bf10787e27364730dd37a42b603cee8d6af7ee", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "3.2", + "repo": "cabal", + "type": "github" + } + }, + "cabal-34": { + "flake": false, + "locked": { + "lastModified": 1645834128, + "narHash": "sha256-wG3d+dOt14z8+ydz4SL7pwGfe7SiimxcD/LOuPCV6xM=", + "owner": "haskell", + "repo": "cabal", + "rev": "5ff598c67f53f7c4f48e31d722ba37172230c462", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "3.4", + "repo": "cabal", + "type": "github" + } + }, + "cabal-36": { + "flake": false, + "locked": { + "lastModified": 1669081697, + "narHash": "sha256-I5or+V7LZvMxfbYgZATU4awzkicBwwok4mVoje+sGmU=", + "owner": "haskell", + "repo": "cabal", + "rev": "8fd619e33d34924a94e691c5fea2c42f0fc7f144", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "3.6", + "repo": "cabal", + "type": "github" + } + }, + "cardano-shell": { + "flake": false, + "locked": { + "lastModified": 1608537748, + "narHash": "sha256-PulY1GfiMgKVnBci3ex4ptk2UNYMXqGjJOxcPy2KYT4=", + "owner": "input-output-hk", + "repo": "cardano-shell", + "rev": "9392c75087cb9a3d453998f4230930dea3a95725", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "cardano-shell", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1672831974, + "narHash": "sha256-z9k3MfslLjWQfnjBtEtJZdq3H7kyi2kQtUThfTgdRk0=", + "owner": "input-output-hk", + "repo": "flake-compat", + "rev": "45f2638735f8cdc40fe302742b79f248d23eb368", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "ref": "hkm/gitlab-fix", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "ghc-8.6.5-iohk": { + "flake": false, + "locked": { + "lastModified": 1600920045, + "narHash": "sha256-DO6kxJz248djebZLpSzTGD6s8WRpNI9BTwUeOf5RwY8=", + "owner": "input-output-hk", + "repo": "ghc", + "rev": "95713a6ecce4551240da7c96b6176f980af75cae", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "ref": "release/8.6.5-iohk", + "repo": "ghc", + "type": "github" + } + }, + "ghc98X": { + "flake": false, + "locked": { + "lastModified": 1696643148, + "narHash": "sha256-E02DfgISH7EvvNAu0BHiPvl1E5FGMDi0pWdNZtIBC9I=", + "ref": "ghc-9.8", + "rev": "443e870d977b1ab6fc05f47a9a17bc49296adbd6", + "revCount": 61642, + "submodules": true, + "type": "git", + "url": "https://gitlab.haskell.org/ghc/ghc" + }, + "original": { + "ref": "ghc-9.8", + "submodules": true, + "type": "git", + "url": "https://gitlab.haskell.org/ghc/ghc" + } + }, + "ghc99": { + "flake": false, + "locked": { + "lastModified": 1701580282, + "narHash": "sha256-drA01r3JrXnkKyzI+owMZGxX0JameMzjK0W5jJE/+V4=", + "ref": "refs/heads/master", + "rev": "f5eb0f2982e9cf27515e892c4bdf634bcfb28459", + "revCount": 62197, + "submodules": true, + "type": "git", + "url": "https://gitlab.haskell.org/ghc/ghc" + }, + "original": { + "submodules": true, + "type": "git", + "url": "https://gitlab.haskell.org/ghc/ghc" + } + }, + "hackage": { + "flake": false, + "locked": { + "lastModified": 1706574159, + "narHash": "sha256-OcE1NT4zQfV4h8Ybq1ttNT+TkXjTV1O2doiCfJzjCbw=", + "owner": "input-output-hk", + "repo": "hackage.nix", + "rev": "ccff69cc942afd51dbdd7466192e3f4cfe09cde2", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "hackage.nix", + "type": "github" + } + }, + "haskellNix": { + "inputs": { + "HTTP": "HTTP", + "cabal-32": "cabal-32", + "cabal-34": "cabal-34", + "cabal-36": "cabal-36", + "cardano-shell": "cardano-shell", + "flake-compat": "flake-compat", + "ghc-8.6.5-iohk": "ghc-8.6.5-iohk", + "ghc98X": "ghc98X", + "ghc99": "ghc99", + "hackage": "hackage", + "hls-1.10": "hls-1.10", + "hls-2.0": "hls-2.0", + "hls-2.2": "hls-2.2", + "hls-2.3": "hls-2.3", + "hls-2.4": "hls-2.4", + "hls-2.5": "hls-2.5", + "hls-2.6": "hls-2.6", + "hpc-coveralls": "hpc-coveralls", + "hydra": "hydra", + "iserv-proxy": "iserv-proxy", + "nix-tools-static": "nix-tools-static", + "nixpkgs": [ + "haskellNix", + "nixpkgs-unstable" + ], + "nixpkgs-2003": "nixpkgs-2003", + "nixpkgs-2105": "nixpkgs-2105", + "nixpkgs-2111": "nixpkgs-2111", + "nixpkgs-2205": "nixpkgs-2205", + "nixpkgs-2211": "nixpkgs-2211", + "nixpkgs-2305": "nixpkgs-2305", + "nixpkgs-2311": "nixpkgs-2311", + "nixpkgs-unstable": "nixpkgs-unstable", + "old-ghc-nix": "old-ghc-nix", + "stackage": "stackage" + }, + "locked": { + "lastModified": 1706575804, + "narHash": "sha256-/2oEg1CD3FtXOsF0dQm/5RLGZ5LwILA5Gnuw/FkNm4w=", + "owner": "input-output-hk", + "repo": "haskell.nix", + "rev": "8bc501003577cf9a1077f04d2dabf58f68b256b6", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "haskell.nix", + "type": "github" + } + }, + "hls-1.10": { + "flake": false, + "locked": { + "lastModified": 1680000865, + "narHash": "sha256-rc7iiUAcrHxwRM/s0ErEsSPxOR3u8t7DvFeWlMycWgo=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "b08691db779f7a35ff322b71e72a12f6e3376fd9", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "1.10.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.0": { + "flake": false, + "locked": { + "lastModified": 1687698105, + "narHash": "sha256-OHXlgRzs/kuJH8q7Sxh507H+0Rb8b7VOiPAjcY9sM1k=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "783905f211ac63edf982dd1889c671653327e441", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.0.0.1", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.2": { + "flake": false, + "locked": { + "lastModified": 1693064058, + "narHash": "sha256-8DGIyz5GjuCFmohY6Fa79hHA/p1iIqubfJUTGQElbNk=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "b30f4b6cf5822f3112c35d14a0cba51f3fe23b85", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.2.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.3": { + "flake": false, + "locked": { + "lastModified": 1695910642, + "narHash": "sha256-tR58doOs3DncFehHwCLczJgntyG/zlsSd7DgDgMPOkI=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "458ccdb55c9ea22cd5d13ec3051aaefb295321be", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.3.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.4": { + "flake": false, + "locked": { + "lastModified": 1699862708, + "narHash": "sha256-YHXSkdz53zd0fYGIYOgLt6HrA0eaRJi9mXVqDgmvrjk=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "54507ef7e85fa8e9d0eb9a669832a3287ffccd57", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.4.0.1", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.5": { + "flake": false, + "locked": { + "lastModified": 1701080174, + "narHash": "sha256-fyiR9TaHGJIIR0UmcCb73Xv9TJq3ht2ioxQ2mT7kVdc=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "27f8c3d3892e38edaef5bea3870161815c4d014c", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.5.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.6": { + "flake": false, + "locked": { + "lastModified": 1705325287, + "narHash": "sha256-+P87oLdlPyMw8Mgoul7HMWdEvWP/fNlo8jyNtwME8E8=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "6e0b342fa0327e628610f2711f8c3e4eaaa08b1e", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.6.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hpc-coveralls": { + "flake": false, + "locked": { + "lastModified": 1607498076, + "narHash": "sha256-8uqsEtivphgZWYeUo5RDUhp6bO9j2vaaProQxHBltQk=", + "owner": "sevanspowell", + "repo": "hpc-coveralls", + "rev": "14df0f7d229f4cd2e79f8eabb1a740097fdfa430", + "type": "github" + }, + "original": { + "owner": "sevanspowell", + "repo": "hpc-coveralls", + "type": "github" + } + }, + "hydra": { + "inputs": { + "nix": "nix", + "nixpkgs": [ + "haskellNix", + "hydra", + "nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1671755331, + "narHash": "sha256-hXsgJj0Cy0ZiCiYdW2OdBz5WmFyOMKuw4zyxKpgUKm4=", + "owner": "NixOS", + "repo": "hydra", + "rev": "f48f00ee6d5727ae3e488cbf9ce157460853fea8", + "type": "github" + }, + "original": { + "id": "hydra", + "type": "indirect" + } + }, + "iserv-proxy": { + "flake": false, + "locked": { + "lastModified": 1691634696, + "narHash": "sha256-MZH2NznKC/gbgBu8NgIibtSUZeJ00HTLJ0PlWKCBHb0=", + "ref": "hkm/remote-iserv", + "rev": "43a979272d9addc29fbffc2e8542c5d96e993d73", + "revCount": 14, + "type": "git", + "url": "https://gitlab.haskell.org/hamishmack/iserv-proxy.git" + }, + "original": { + "ref": "hkm/remote-iserv", + "type": "git", + "url": "https://gitlab.haskell.org/hamishmack/iserv-proxy.git" + } + }, + "lowdown-src": { + "flake": false, + "locked": { + "lastModified": 1633514407, + "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=", + "owner": "kristapsdz", + "repo": "lowdown", + "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8", + "type": "github" + }, + "original": { + "owner": "kristapsdz", + "repo": "lowdown", + "type": "github" + } + }, + "nix": { + "inputs": { + "lowdown-src": "lowdown-src", + "nixpkgs": "nixpkgs", + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1661606874, + "narHash": "sha256-9+rpYzI+SmxJn+EbYxjGv68Ucp22bdFUSy/4LkHkkDQ=", + "owner": "NixOS", + "repo": "nix", + "rev": "11e45768b34fdafdcf019ddbd337afa16127ff0f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "2.11.0", + "repo": "nix", + "type": "github" + } + }, + "nix-tools-static": { + "flake": false, + "locked": { + "lastModified": 1706266250, + "narHash": "sha256-9t+GRk3eO9muCtKdNAwBtNBZ5dH1xHcnS17WaQyftwA=", + "owner": "input-output-hk", + "repo": "haskell-nix-example", + "rev": "580cb6db546a7777dad3b9c0fa487a366c045c4e", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "ref": "nix", + "repo": "haskell-nix-example", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1657693803, + "narHash": "sha256-G++2CJ9u0E7NNTAi9n5G8TdDmGJXcIjkJ3NF8cetQB8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "365e1b3a859281cf11b94f87231adeabbdd878a2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-22.05-small", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2003": { + "locked": { + "lastModified": 1620055814, + "narHash": "sha256-8LEHoYSJiL901bTMVatq+rf8y7QtWuZhwwpKE2fyaRY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1db42b7fe3878f3f5f7a4f2dc210772fd080e205", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-20.03-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2105": { + "locked": { + "lastModified": 1659914493, + "narHash": "sha256-lkA5X3VNMKirvA+SUzvEhfA7XquWLci+CGi505YFAIs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "022caabb5f2265ad4006c1fa5b1ebe69fb0c3faf", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-21.05-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2111": { + "locked": { + "lastModified": 1659446231, + "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-21.11-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2205": { + "locked": { + "lastModified": 1685573264, + "narHash": "sha256-Zffu01pONhs/pqH07cjlF10NnMDLok8ix5Uk4rhOnZQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "380be19fbd2d9079f677978361792cb25e8a3635", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-22.05-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2211": { + "locked": { + "lastModified": 1688392541, + "narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-22.11-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2305": { + "locked": { + "lastModified": 1701362232, + "narHash": "sha256-GVdzxL0lhEadqs3hfRLuj+L1OJFGiL/L7gCcelgBlsw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d2332963662edffacfddfad59ff4f709dde80ffe", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-23.05-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2311": { + "locked": { + "lastModified": 1701386440, + "narHash": "sha256-xI0uQ9E7JbmEy/v8kR9ZQan6389rHug+zOtZeZFiDJk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "293822e55ec1872f715a66d0eda9e592dc14419f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-23.11-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1694822471, + "narHash": "sha256-6fSDCj++lZVMZlyqOe9SIOL8tYSBz1bI8acwovRwoX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "47585496bcb13fb72e4a90daeea2f434e2501998", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "47585496bcb13fb72e4a90daeea2f434e2501998", + "type": "github" + } + }, + "old-ghc-nix": { + "flake": false, + "locked": { + "lastModified": 1631092763, + "narHash": "sha256-sIKgO+z7tj4lw3u6oBZxqIhDrzSkvpHtv0Kki+lh9Fg=", + "owner": "angerman", + "repo": "old-ghc-nix", + "rev": "af48a7a7353e418119b6dfe3cd1463a657f342b8", + "type": "github" + }, + "original": { + "owner": "angerman", + "ref": "master", + "repo": "old-ghc-nix", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "haskellNix": "haskellNix", + "nixpkgs": [ + "haskellNix", + "nixpkgs-unstable" + ] + } + }, + "stackage": { + "flake": false, + "locked": { + "lastModified": 1706573344, + "narHash": "sha256-nOc8eVWcS//QjV4tdZlJVMWPyGauD71BNdCXjvTRXDs=", + "owner": "input-output-hk", + "repo": "stackage.nix", + "rev": "c911e99f7ab959a8d2b83c038a803c255a6d215a", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "stackage.nix", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..c70f8d2 --- /dev/null +++ b/flake.nix @@ -0,0 +1,93 @@ +{ + description = "hakyll-nix-template"; + + nixConfig = { + allow-import-from-derivation = "true"; + bash-prompt = "[hakyll-nix]λ "; + extra-substituters = [ + "https://cache.iog.io" + ]; + extra-trusted-public-keys = [ + "hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=" + ]; + }; + + inputs.haskellNix.url = "github:input-output-hk/haskell.nix"; + inputs.nixpkgs.follows = "haskellNix/nixpkgs-unstable"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + + outputs = { self, nixpkgs, flake-utils, haskellNix }: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ haskellNix.overlay + (final: prev: { + hakyllProject = final.haskell-nix.project' { + src = ./ssg; + compiler-nix-name = "ghc948"; + modules = [{ doHaddock = false; }]; + shell.buildInputs = [ + hakyll-site + ]; + shell.tools = { + cabal = "latest"; + hlint = "latest"; + haskell-language-server = "latest"; + }; + }; + }) + ]; + + pkgs = import nixpkgs { + inherit overlays system; + inherit (haskellNix) config; + }; + + flake = pkgs.hakyllProject.flake {}; + + executable = "ssg:exe:hakyll-site"; + + hakyll-site = flake.packages.${executable}; + + website = pkgs.stdenv.mkDerivation { + name = "website"; + buildInputs = []; + src = pkgs.nix-gitignore.gitignoreSourcePure [ + ./.gitignore + ".git" + ".github" + ] ./.; + + # LANG and LOCALE_ARCHIVE are fixes pulled from the community: + # https://github.com/jaspervdj/hakyll/issues/614#issuecomment-411520691 + # https://github.com/NixOS/nix/issues/318#issuecomment-52986702 + # https://github.com/MaxDaten/brutal-recipes/blob/source/default.nix#L24 + LANG = "en_US.UTF-8"; + LOCALE_ARCHIVE = pkgs.lib.optionalString + (pkgs.buildPlatform.libc == "glibc") + "${pkgs.glibcLocales}/lib/locale/locale-archive"; + + buildPhase = '' + ${flake.packages.${executable}}/bin/hakyll-site build --verbose + ''; + + installPhase = '' + mkdir -p "$out/dist" + cp -a dist/. "$out/dist" + ''; + }; + + in flake // rec { + apps = { + default = flake-utils.lib.mkApp { + drv = hakyll-site; + exePath = "/bin/hakyll-site"; + }; + }; + + packages = { + inherit hakyll-site website; + default = website; + }; + } + ); +} diff --git a/src/CNAME b/src/CNAME new file mode 100644 index 0000000..1ce262e --- /dev/null +++ b/src/CNAME @@ -0,0 +1 @@ +mywebsite123456789123456789.com diff --git a/src/_config.yaml b/src/_config.yaml new file mode 100644 index 0000000..1f83507 --- /dev/null +++ b/src/_config.yaml @@ -0,0 +1,8 @@ +# This is a Jekyll config file. Jekyll is used by GitHub +# Pages to manage static site generation / distribution. +# If you don't use GitHub Pages or don't need to customize +# it, you can delete this file and remove its entry in +# `../ssg/src/Main.hs`. +# +# https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll +include: [] diff --git a/src/css/default.css b/src/css/default.css new file mode 100644 index 0000000..23bb11d --- /dev/null +++ b/src/css/default.css @@ -0,0 +1,54 @@ +:root { + font-size: 62.5%; + box-sizing: border-box; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} +*, +*:before, +*:after { + box-sizing: inherit; +} +html, +body { + min-height: 100vh; +} +body { + font-kerning: normal; + -moz-font-feature-settings: "kern", "liga", "clig", "calt"; + -ms-font-feature-settings: "kern", "liga", "clig", "calt"; + -webkit-font-feature-settings: "kern", "liga", "clig", "calt"; + font-feature-settings: "kern", "liga", "clig", "calt"; + scroll-behavior: smooth; + font-size: 2rem; +} +body, +input, +button { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +h1, +h2 { + font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; +} +h1 { + font-size: 4.0rem; +} +h2 { + font-size: 2.6rem; +} +small, +p { + font-family: Tahoma, Arial, sans-serif; +} +small { + font-size: 1.6rem; + font-style: italic; +} +p { + font-size: 1.8rem; +} +pre.sourceCode { + padding: 2rem 1.5rem; +} diff --git a/src/favicon.ico b/src/favicon.ico new file mode 100644 index 0000000..2096d33 Binary files /dev/null and b/src/favicon.ico differ diff --git a/src/images/robert-pearce-UwHN0jU_YqQ-unsplash-800w.jpg b/src/images/robert-pearce-UwHN0jU_YqQ-unsplash-800w.jpg new file mode 100644 index 0000000..5a35972 Binary files /dev/null and b/src/images/robert-pearce-UwHN0jU_YqQ-unsplash-800w.jpg differ diff --git a/src/images/waiheke-stony-batter.jpg b/src/images/waiheke-stony-batter.jpg new file mode 100644 index 0000000..eb9211d Binary files /dev/null and b/src/images/waiheke-stony-batter.jpg differ diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..c705cdc --- /dev/null +++ b/src/index.html @@ -0,0 +1,29 @@ +--- +desc: "This is me saying hello to the world" +image: "./images/robert-pearce-UwHN0jU_YqQ-unsplash-800w.jpg" +lang: "en" +stylesheet: "default" +title: "Hello, world!" +--- + +
+

Hello, world!

+ A woman sitting on a bench amongst trees at the end of a boardwalk leading to a pond with mountains in the background +
+
+
+

Blog Posts

+ +
+
diff --git a/src/js/script.js b/src/js/script.js new file mode 100644 index 0000000..9efe503 --- /dev/null +++ b/src/js/script.js @@ -0,0 +1,3 @@ +;(function() { + console.log('Hello, world!'); +})(); diff --git a/src/posts/2020-09-21-hello-world.md b/src/posts/2020-09-21-hello-world.md new file mode 100644 index 0000000..1cdd699 --- /dev/null +++ b/src/posts/2020-09-21-hello-world.md @@ -0,0 +1,26 @@ +--- +author: "My name" +authorTwitter: "@MyName" +desc: "I announce myself to the world" +image: "./images/waiheke-stony-batter.jpg" +keywords: "hello, announcement" +lang: "en" +title: "Hello, world!" +updated: "2020-09-22T12:00:00Z" +--- + +Hello, world! I am here! + +Grapevines among rolling hills leading to the sea + +Haskell, for example: + +```haskell +toSlug :: T.Text -> T.Text +toSlug = + T.intercalate (T.singleton '-') . T.words . T.toLower . clean +``` diff --git a/src/posts/2020-09-22-hola-mundo.md b/src/posts/2020-09-22-hola-mundo.md new file mode 100644 index 0000000..3e17349 --- /dev/null +++ b/src/posts/2020-09-22-hola-mundo.md @@ -0,0 +1,26 @@ +--- +author: "Mi nombre" +authorTwitter: "@MiNombre" +desc: "Me anuncio al mundo" +image: "./images/waiheke-stony-batter.jpg" +keywords: "hola, anuncio" +lang: "es" +title: "¡Hola Mundo!" +updated: "2020-09-23T12:00:00Z" +--- + +¡Hola Mundo! ¡Estoy aquí! + +Grapevines among rolling hills leading to the sea + +Haskell, por ejemplo: + +```haskell +toSlug :: T.Text -> T.Text +toSlug = + T.intercalate (T.singleton '-') . T.words . T.toLower . clean +``` diff --git a/src/robots.txt b/src/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/src/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/src/templates/default.html b/src/templates/default.html new file mode 100644 index 0000000..67a44af --- /dev/null +++ b/src/templates/default.html @@ -0,0 +1,53 @@ + + + + $title$ + + + + + $if(author)$ + + $endif$ + $if(keywords)$ + + $endif$ + + + + + + $if(image)$ + + $endif$ + $if(type)$ + + $else$ + + $endif$ + + $if(image)$ + + + $endif$ + + + + $if(authorTwitter)$ + + $endif$ + + + + + + + + + + + + $body$ + + + diff --git a/src/templates/post.html b/src/templates/post.html new file mode 100644 index 0000000..4b64fd6 --- /dev/null +++ b/src/templates/post.html @@ -0,0 +1,15 @@ +
+
+
+

+ $title$ +

+
+ $date$ $if(updated)$(updated: $updated$)$endif$ +
+
+
+ $body$ +
+
+
diff --git a/src/templates/sitemap.xml b/src/templates/sitemap.xml new file mode 100644 index 0000000..10b9945 --- /dev/null +++ b/src/templates/sitemap.xml @@ -0,0 +1,16 @@ + + + + $root$ + daily + 1.0 + +$for(pages)$ + + $root$$url$ + $if(updated)$$updated$$else$$if(date)$$date$$endif$$endif$ + weekly + 0.8 + +$endfor$ + diff --git a/ssg/LICENSE b/ssg/LICENSE new file mode 100644 index 0000000..1009f96 --- /dev/null +++ b/ssg/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2020, Robert Pearce +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ssg/src/Main.hs b/ssg/src/Main.hs new file mode 100644 index 0000000..14494ef --- /dev/null +++ b/ssg/src/Main.hs @@ -0,0 +1,264 @@ +{-# LANGUAGE OverloadedStrings #-} + +import Control.Monad (forM_) +import Data.List (isPrefixOf, isSuffixOf) +import Data.Maybe (fromMaybe) +import Hakyll +import qualified Data.Text as T +import qualified Data.Text.Slugger as Slugger +import System.FilePath (takeFileName) +import Text.Pandoc + ( Extension (Ext_fenced_code_attributes, Ext_footnotes, Ext_gfm_auto_identifiers, Ext_implicit_header_references, Ext_smart), + Extensions, + ReaderOptions, + WriterOptions (writerHighlightStyle), + extensionsFromList, + githubMarkdownExtensions, + readerExtensions, + writerExtensions, + ) +import Text.Pandoc.Highlighting (Style, breezeDark, styleToCss) + +-------------------------------------------------------------------------------- +-- PERSONALIZATION + +mySiteName :: String +mySiteName = "My Site Name" + +mySiteRoot :: String +mySiteRoot = "https://my-site.com" + +myFeedTitle :: String +myFeedTitle = "My Feed Title" + +myFeedDescription :: String +myFeedDescription = "My Site Description" + +myFeedAuthorName :: String +myFeedAuthorName = "My Name" + +myFeedAuthorEmail :: String +myFeedAuthorEmail = "me@myemail.com" + +myFeedRoot :: String +myFeedRoot = mySiteRoot + +-------------------------------------------------------------------------------- +-- CONFIG + +-- Default configuration: https://github.com/jaspervdj/hakyll/blob/cd74877d41f41c4fba27768f84255e797748a31a/lib/Hakyll/Core/Configuration.hs#L101-L125 +config :: Configuration +config = + defaultConfiguration + { destinationDirectory = "dist" + , ignoreFile = ignoreFile' + , previewHost = "127.0.0.1" + , previewPort = 8000 + , providerDirectory = "src" + , storeDirectory = "ssg/_cache" + , tmpDirectory = "ssg/_tmp" + } + where + ignoreFile' path + | "." `isPrefixOf` fileName = False + | "#" `isPrefixOf` fileName = True + | "~" `isSuffixOf` fileName = True + | ".swp" `isSuffixOf` fileName = True + | otherwise = False + where + fileName = takeFileName path + +-------------------------------------------------------------------------------- +-- BUILD + +main :: IO () +main = hakyllWith config $ do + forM_ + [ "CNAME" + , "favicon.ico" + , "robots.txt" + , "_config.yml" + , "images/*" + , "js/*" + , "fonts/*" + ] + $ \f -> match f $ do + route idRoute + compile copyFileCompiler + + match "css/*" $ do + route idRoute + compile compressCssCompiler + + match "posts/*" $ do + let ctx = constField "type" "article" <> postCtx + + route $ metadataRoute titleRoute + compile $ + pandocCompilerCustom + >>= loadAndApplyTemplate "templates/post.html" ctx + >>= saveSnapshot "content" + >>= loadAndApplyTemplate "templates/default.html" ctx + + match "index.html" $ do + route idRoute + compile $ do + posts <- recentFirst =<< loadAll "posts/*" + + let indexCtx = + listField "posts" postCtx (return posts) + <> constField "root" mySiteRoot + <> constField "feedTitle" myFeedTitle + <> constField "siteName" mySiteName + <> defaultContext + + getResourceBody + >>= applyAsTemplate indexCtx + >>= loadAndApplyTemplate "templates/default.html" indexCtx + + match "templates/*" $ + compile templateBodyCompiler + + create ["sitemap.xml"] $ do + route idRoute + compile $ do + posts <- recentFirst =<< loadAll "posts/*" + + let pages = posts + sitemapCtx = + constField "root" mySiteRoot + <> constField "siteName" mySiteName + <> listField "pages" postCtx (return pages) + + makeItem ("" :: String) + >>= loadAndApplyTemplate "templates/sitemap.xml" sitemapCtx + + create ["rss.xml"] $ do + route idRoute + compile (feedCompiler renderRss) + + create ["atom.xml"] $ do + route idRoute + compile (feedCompiler renderAtom) + + create ["css/code.css"] $ do + route idRoute + compile (makeStyle pandocHighlightStyle) + +-------------------------------------------------------------------------------- +-- COMPILER HELPERS + +makeStyle :: Style -> Compiler (Item String) +makeStyle = + makeItem . compressCss . styleToCss + +-------------------------------------------------------------------------------- +-- CONTEXT + +feedCtx :: Context String +feedCtx = + titleCtx + <> postCtx + <> bodyField "description" + +postCtx :: Context String +postCtx = + constField "root" mySiteRoot + <> constField "feedTitle" myFeedTitle + <> constField "siteName" mySiteName + <> dateField "date" "%Y-%m-%d" + <> defaultContext + +titleCtx :: Context String +titleCtx = + field "title" updatedTitle + +-------------------------------------------------------------------------------- +-- TITLE HELPERS + +replaceAmp :: String -> String +replaceAmp = + replaceAll "&" (const "&") + +replaceTitleAmp :: Metadata -> String +replaceTitleAmp = + replaceAmp . safeTitle + +safeTitle :: Metadata -> String +safeTitle = + fromMaybe "no title" . lookupString "title" + +updatedTitle :: Item a -> Compiler String +updatedTitle = + fmap replaceTitleAmp . getMetadata . itemIdentifier + +-------------------------------------------------------------------------------- +-- PANDOC + +pandocCompilerCustom :: Compiler (Item String) +pandocCompilerCustom = + pandocCompilerWith pandocReaderOpts pandocWriterOpts + +pandocExtensionsCustom :: Extensions +pandocExtensionsCustom = + githubMarkdownExtensions + <> extensionsFromList + [ Ext_fenced_code_attributes + , Ext_gfm_auto_identifiers + , Ext_implicit_header_references + , Ext_smart + , Ext_footnotes + ] + +pandocReaderOpts :: ReaderOptions +pandocReaderOpts = + defaultHakyllReaderOptions + { readerExtensions = pandocExtensionsCustom + } + +pandocWriterOpts :: WriterOptions +pandocWriterOpts = + defaultHakyllWriterOptions + { writerExtensions = pandocExtensionsCustom + , writerHighlightStyle = Just pandocHighlightStyle + } + +pandocHighlightStyle :: Style +pandocHighlightStyle = + breezeDark -- https://hackage.haskell.org/package/pandoc/docs/Text-Pandoc-Highlighting.html + +-------------------------------------------------------------------------------- +-- FEEDS + +type FeedRenderer = + FeedConfiguration -> + Context String -> + [Item String] -> + Compiler (Item String) + +feedCompiler :: FeedRenderer -> Compiler (Item String) +feedCompiler renderer = + renderer feedConfiguration feedCtx + =<< recentFirst + =<< loadAllSnapshots "posts/*" "content" + +feedConfiguration :: FeedConfiguration +feedConfiguration = + FeedConfiguration + { feedTitle = myFeedTitle + , feedDescription = myFeedDescription + , feedAuthorName = myFeedAuthorName + , feedAuthorEmail = myFeedAuthorEmail + , feedRoot = myFeedRoot + } + +-------------------------------------------------------------------------------- +-- CUSTOM ROUTE + +fileNameFromTitle :: Metadata -> FilePath +fileNameFromTitle = + T.unpack . (`T.append` ".html") . Slugger.toSlug . T.pack . safeTitle + +titleRoute :: Metadata -> Routes +titleRoute = + constRoute . fileNameFromTitle diff --git a/ssg/ssg.cabal b/ssg/ssg.cabal new file mode 100644 index 0000000..47cea1f --- /dev/null +++ b/ssg/ssg.cabal @@ -0,0 +1,29 @@ +cabal-version: 3.6 + +name: ssg +version: 0.1.0.0 +build-type: Simple +license: BSD-3-Clause +license-file: LICENSE + +executable hakyll-site + default-language: Haskell2010 + main-is: Main.hs + hs-source-dirs: src + build-depends: base == 4.* + , hakyll == 4.15.* + , filepath >= 1.0 + , pandoc >= 2.11 + , slugger >= 0.1.0.2 + , text >= 1 && < 3 + ghc-options: -Wall + -Wcompat + -Widentities + -Wincomplete-record-updates + -Wincomplete-uni-patterns + -Wpartial-fields + -Wredundant-constraints + -O2 + -threaded + -rtsopts + -with-rtsopts=-N