From d364237e05a0d68d09ef5f7e395038364cf28249 Mon Sep 17 00:00:00 2001 From: Pagwin Date: Sat, 20 Jul 2024 16:49:21 -0400 Subject: [PATCH] initial commit after moving out of repo --- .gitignore | 1 + CHANGELOG.md | 5 +++ LICENSE | 20 ++++++++++ app/Main.hs | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ psb.cabal | 77 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 204 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100755 app/Main.hs create mode 100644 psb.cabal diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48a004c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +dist-newstyle diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b45b417 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for psb + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8aa9f8a --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2024 Pagwin + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (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: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +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/app/Main.hs b/app/Main.hs new file mode 100755 index 0000000..6c875b8 --- /dev/null +++ b/app/Main.hs @@ -0,0 +1,101 @@ +-- pulling heavily from https://abhinavsarkar.net/posts/static-site-generator-using-shake/ +-- docs: +-- https://hackage.haskell.org/package/pandoc-3.2.1/docs/doc-index-All.html +-- https://hackage.haskell.org/package/mustache-2.4.2/docs/doc-index.html +-- +{-# LANGUAGE ApplicativeDo, DataKinds, DeriveGeneric #-} +{-# LANGUAGE DerivingVia, LambdaCase, TypeApplications #-} + +module Main where + +import Control.Monad (forM, void) +import Data.Aeson.Types (Result (..)) +import Data.List (nub, sortOn) +import Data.Text (Text) +import Data.Time (UTCTime, defaultTimeLocale, formatTime, parseTimeM) +import Deriving.Aeson +import Deriving.Aeson.Stock (PrefixedSnake) +import Development.Shake (Action, Rules, (%>), (|%>), (~>)) +import Development.Shake.FilePath ((<.>), ()) +import Text.Pandoc (Block (Plain), Meta (..), MetaValue (..), Pandoc (..)) +import qualified Data.Aeson.Types as A +import qualified Data.HashMap.Strict as HM +import qualified Data.Ord as Ord +import qualified Data.Text as T +import qualified Development.Shake as Shake +import qualified Development.Shake.FilePath as Shake +import qualified Text.Mustache as Mus +import qualified Text.Mustache.Compile as Mus +import qualified Text.Pandoc as Pandoc + +-- target = thing we want +-- Rule = pattern of thing being made + actions to produce the thing +-- Action = actions to produce a thing + +main :: IO () +main = Shake.shakeArgs Shake.shakeOptions $ do + Shake.withTargetDocs "Build the site" $ + "build" ~> buildSite + Shake.withTargetDocs "Clean the built site" $ + "clean" ~> Shake.removeFilesAfter outputDir ["//*"] + +outputDir :: String +outputDir = "publish" + +buildSite :: Action () +buildSite = do + -- static files + assetPaths <- Shake.getDirectoryFiles "" assetGlobs + -- path concat each asset path so it's output into the outputDir + Shake.need $ map (outputDir ) assetPaths + + -- take the misc pages which aren't blog posts and make their html files + Shake.need $ map indexHtmlOutputPath pagePaths + + -- handle posts + postPaths <- Shake.getDirectoryFiles "" postGlobs + Shake.need $ map indexHtmlOutputPath postPaths + + -- remaining pages, index.xml = rss feed + Shake.need $ map (outputDir ) ["index.html", "index.xml"] + +-- make a rule of the pattern outputDir/asset_name which copes from outputDir/../pages +assets :: Rules () +assets = map (outputDir ) assetGlobs |%> \target -> do + let src = Shake.dropDirectory1 target "pages" + Shake.copyFileChanged src target + Shake.putInfo $ "Copied " <> target <> " from " <> src + +typstToHtml :: FilePath -> Action Text +typstToHtml filePath = do + content <- Shake.readFile' filePath + Shake.quietly . Shake.traced "Typst to HTML" $ do + doc <- runPandoc . Pandoc.readTypst readerOptions . T.pack $ content + + runPandoc . Pandoc.writeHtml5String writerOptions $ doc + where + readerOptions = + Pandoc.def {Pandoc.readerExtensions = Pandoc.pandocExtensions} + writerOptions = + Pandoc.def {Pandoc.writerExtensions = Pandoc.pandocExtensions} + +data Page = Page {pageTitle :: Text, pageContent :: Text} + deriving (Show, Generic) + deriving (ToJSON) via PrefixedSnake "page" Page + +assetGlobs :: [String] +assetGlobs = ["static/*"] + +pagePaths :: [String] +pagePaths = ["about.md", "contact.md"] + +postGlobs :: [String] +postGlobs = ["posts/*.typ"] + +runPandoc action = + Pandoc.runIO (Pandoc.setVerbosity Pandoc.ERROR >> action) + >>= either (fail . show) return + +indexHtmlOutputPath :: FilePath -> FilePath +indexHtmlOutputPath srcPath = + outputDir Shake.dropExtension srcPath "index.html" diff --git a/psb.cabal b/psb.cabal new file mode 100644 index 0000000..2e9a8e1 --- /dev/null +++ b/psb.cabal @@ -0,0 +1,77 @@ +cabal-version: 3.4 +-- The cabal-version field refers to the version of the .cabal specification, +-- and can be different from the cabal-install (the tool) version and the +-- Cabal (the library) version you are using. As such, the Cabal (the library) +-- version used must be equal or greater than the version stated in this field. +-- Starting from the specification version 2.2, the cabal-version field must be +-- the first thing in the cabal file. + +-- Initial package description 'psb' generated by +-- 'cabal init'. For further documentation, see: +-- http://haskell.org/cabal/users-guide/ +-- +-- The name of the package. +name: psb + +-- The package version. +-- See the Haskell package versioning policy (PVP) for standards +-- guiding when and how versions should be incremented. +-- https://pvp.haskell.org +-- PVP summary: +-+------- breaking API changes +-- | | +----- non-breaking API additions +-- | | | +--- code changes with no API change +version: 0.1.0.0 + +-- A short (one-line) description of the package. +-- synopsis: + +-- A longer description of the package. +-- description: + +-- The license under which the package is released. +license: MIT + +-- The file containing the license text. +license-file: LICENSE + +-- The package author(s). +author: Pagwin + +-- An email address to which users can send suggestions, bug reports, and patches. +maintainer: dev@pagwin.xyz + +-- A copyright notice. +-- copyright: +category: Web +build-type: Simple + +-- Extra doc files to be distributed with the package, such as a CHANGELOG or a README. +extra-doc-files: CHANGELOG.md + +-- Extra source files to be distributed with the package, such as examples, or a tutorial module. +-- extra-source-files: + +common warnings + ghc-options: -Wall + +executable psb + -- Import common warning flags. + import: warnings + + -- .hs or .lhs file containing the Main module. + main-is: Main.hs + + -- Modules included in this executable, other than Main. + -- other-modules: + + -- LANGUAGE extensions used by modules in this package. + -- other-extensions: + + -- Other library packages from which modules are imported. + build-depends: base ^>=4.17.2.1, mustache ^>=2.4.2, pandoc ^>=3.2.1, shake ^>= 0.19.8, deriving-aeson ^>= 0.2.9, aeson, text, time, unordered-containers + + -- Directories containing source files. + hs-source-dirs: app + + -- Base language which the package is written in. + default-language: Haskell2010