🐙 Templated web page generator for your git repositories
git clone https://github.com/m-col/gitja
Files | Refs | Readme | License

Commit ca65149efd444d8d2f4875112039318731dfcb17
Parent: a4bf6a6922ecae0eafca619e9e972335d6c32d13
Author: mcol <mcol@posteo.net>
Date: 2021-11-22 00:15:50 +0000
Committer: mcol <mcol@posteo.net>
Committed: 2021-11-22 00:15:50 +0000

Copy non-html files from templateDir to outputDir

templates/style.css Added

@@ -0,0 +1,169 @@
+/*
+Credit to much of the styling here goes to stagit: https://codemadness.org/git/stagit/
+*/
+
+@viewport {
+    width: device-width;
+    zoom: 1.0;
+}
+
+html {
+    color: #000;
+    font-family: monospace;
+    font-size: 1em;
+}
+
+body {
+    max-width: 900px;
+}
+
+p {
+    margin: 15px 0;
+}
+
+li {
+    list-style-type: square;
+}
+
+h1, h2 {
+    font-size: 1em;
+    margin: 0;
+}
+
+h2 {
+    font-weight: bold;
+    text-decoration: underline;
+}
+
+::selection {
+    background: #5D479D;
+    color: #fff;
+}
+
+table td {
+    padding: 0 0.4em;
+}
+
+td.link {
+    text-align: right;
+}
+
+a:target {
+    background-color: #ddd;
+}
+
+#avatar {
+    width: 32px;
+    height: 32px;
+}
+
+a.d, a.h, a.i, a.line {
+    text-decoration: none;
+}
+
+#blob a, .desc {
+    color: #777;
+}
+
+#blob a:hover {
+    color: blue;
+    text-decoration: none;
+}
+
+table thead td {
+    font-weight: bold;
+}
+
+#content table td {
+    vertical-align: top;
+    white-space: nowrap;
+}
+
+#head {
+    width: 100%;
+}
+
+#branches tr:hover td,
+#tags tr:hover td,
+#index tr:hover td,
+#log tr:hover td,
+#files tr:hover td {
+    background-color: #eee;
+}
+
+#index tr td:nth-child(2),
+#tags tr td:nth-child(3),
+#branches tr td:nth-child(3),
+#log tr td:nth-child(2) {
+    white-space: normal;
+}
+
+td.num {
+    text-align: right;
+}
+
+hr {
+    border: 0;
+    border-top: 1px solid #777;
+    height: 1px;
+}
+
+pre a.h {
+    color: #00a;
+}
+
+.A,
+span.i,
+pre a.i {
+    color: #070;
+}
+
+.D,
+span.d,
+pre a.d {
+    color: #e00;
+}
+
+pre a.h:hover,
+pre a.i:hover,
+pre a.d:hover {
+    text-decoration: none;
+}
+
+.highlight, code {
+    background: #eeeeef;
+    color: black;
+}
+
+.highlight {
+    white-space: pre-wrap;
+    word-wrap: break-word;
+}
+
+.c, .ch, .cm, .cp, .cpf, .c1, .gh, .gp
+{ color: #5D479D } /* comments */
+
+.err, .se, .o
+{ color: #a53c21 } /* dark red */
+
+.sh, .si, .sx, .sr, .s1, .ss, .cs, .gd, .dl,
+.s2, .nc, .vc, .vg, .vi, .vm, .nv, .sc, .s
+{ color: #8f4ff0 } /* bright pink */
+
+.kn, .nb, .mb, .mf, .mh, .mi, .mo, .bp, .il, .m
+{ color: #406794 } /* keywords (exit, eval) */
+
+.kt
+{ color: #3e3e73 } /* light grey */
+
+.kc, .k, .ow, .kp, .kr
+{ color: #406794 } /* key words */
+
+.esc, .l, .n, .x, .p, .gs, .ld, .na, .no, .ge
+.nd, .ni, .nf, .nl, .nn, .nx, .py, .nt, .w, .fm, .g
+{ color: black }
+
+.ne { color: #5fd75f }
+
+.gh, .gp, .cs, .gu, .ne, .cs
+{ font-weight: bold }

src/Templates.hs Modified

@@ -19,14 +19,15 @@
     generate,
 ) where
 
-import Control.Monad (filterM, void)
+import Control.Monad (void, (<=<))
 import Data.Char (toLower)
 import qualified Data.HashMap.Strict as HashMap
 import Data.List (isSuffixOf)
 import Data.Maybe (catMaybes)
 import Data.Text (Text, unpack)
-import System.Directory (doesFileExist, getDirectoryContents)
-import System.FilePath ((</>))
+import Path (Abs, Dir, File, Path, dirname, filename, parseAbsDir, toFilePath, (</>))
+import Path.IO (copyDirRecur, copyFile, ensureDir, listDir)
+import System.Directory (makeAbsolute)
 import System.IO.Error (tryIOError)
 import qualified Text.Ginger.AST as G
 import Text.Ginger.GVal (GVal)
@@ -60,9 +61,9 @@
 -}
 loadTemplates :: Bool -> Config -> IO Env
 loadTemplates force config = do
-    -- Custom templates
-    files <- getFiles config
-    templates <- mapM loadTemplate files
+    -- Load files from template directory
+    templateFiles <- getFiles config
+    templates <- mapM loadTemplate (fmap toFilePath templateFiles)
     -- Scoped templates
     indexT <- loadTemplate . indexTemplate $ config
     commitT <- loadTemplate . commitTemplate $ config
@@ -113,39 +114,54 @@
 includeResolver path = either (const Nothing) Just <$> tryIOError (readFile path)
 
 {-
-This is used to filter files in the template directory so that we only try to load
-HTML/CSS/JS files.
+getFiles will look inside the template directory and generate a list of paths to likely
+valid template files and another for static files.
+
+It's not very pretty, but we also copy the static files and folders from here because
+I'm too lazy to work with Path too much.
 -}
-isTemplate :: Config -> FilePath -> IO Bool
-isTemplate config path = (&&) (isTemplate' (map toLower path)) <$> doesFileExist path
+getFiles :: Config -> IO [Path Abs File]
+getFiles config = do
+    (dirs, files) <- ls . templateDirectory $ config
+    let files' = filter (not . isSuffixOf "include" . toFilePath) files
+    let templates = filter (isTemplate config) files'
+    let statics = filter (`notElem` templates) files'
+    output <- parseAbsDir <=< makeAbsolute . outputDirectory $ config
+    ensureDir output
+    copyStaticDirs output dirs
+    copyStaticFiles output statics
+    return templates
   where
-    isTemplate' :: FilePath -> Bool
-    isTemplate' p =
-        not (isTargeted config p) && or (flip isSuffixOf p <$> ["html", "css", "js"])
+    -- This gets fully qualified paths of the directory's contents
+    ls :: FilePath -> IO ([Path Abs Dir], [Path Abs File])
+    ls = listDir <=< parseAbsDir <=< makeAbsolute
 
 {-
-This is used to filter files in the template directory to exclude those specified by the
-config settings ``indexTemplate``, ``commitTemplate`` or ``fileTemplate``.
+This is used to filter files in the template directory so that we only try to load HTML
+files.
 -}
-isTargeted :: Config -> FilePath -> Bool
-isTargeted config path =
-    path == indexTemplate config
-        || path == commitTemplate config
-        || path == fileTemplate config
+isTemplate :: Config -> Path Abs File -> Bool
+isTemplate config = isTemplate' . map toLower . toFilePath
+  where
+    isTemplate' :: FilePath -> Bool
+    isTemplate' p = isSuffixOf "html" p && not (isTargeted config p)
+    isTargeted :: Config -> FilePath -> Bool
+    isTargeted c p = p `elem` [indexTemplate c, commitTemplate c, fileTemplate c]
 
 {-
-This wraps getDirectoryContents so that we get a list of fully qualified paths of the
-directory's contents.
+These copies static files/folders into the output folder unchanged.
 -}
-listTemplates :: FilePath -> IO [FilePath]
-listTemplates = (fmap . fmap . (</>)) <*> getDirectoryContents
+copyStaticFiles :: Path Abs Dir -> [Path Abs File] -> IO ()
+copyStaticFiles output = mapM_ copy
+  where
+    copy :: Path Abs File -> IO ()
+    copy path = copyFile path $ output </> filename path
 
-{-
-getFiles will look inside the template directory and generate a list of paths to likely
-valid template files.
--}
-getFiles :: Config -> IO [FilePath]
-getFiles = ((>>=) . listTemplates . templateDirectory) <*> (filterM . isTemplate)
+copyStaticDirs :: Path Abs Dir -> [Path Abs Dir] -> IO ()
+copyStaticDirs output = mapM_ copy
+  where
+    copy :: Path Abs Dir -> IO ()
+    copy path = copyDirRecur path $ output </> dirname path
 
 {-
 This function gets the output HTML data and is responsible for saving it to file.

gitserve.cabal Modified

@@ -28,6 +28,8 @@
                      , gitlib
                      , gitlib-libgit2
                      , optparse-applicative
+                     , path
+                     , path-io
                      , tagged
                      , text
                      , transformers