-- |
-- Description: Configuration and rules for generating the web site.
-- Copyright: Copyright (C) 2023 Yoo Chung
-- License: All rights reserved
-- Maintainer: web@chungyc.org
--
-- Everything I need to generate my site with Hakyll.
-- These are used in [@app/Site.hs@](https://github.com/chungyc/site-personal/blob/main/app/Site.hs)
-- to build a custom @site@ executable, using the 'hakyllWith' function.
module Web.Site (config, rules) where

import Data.Text qualified as Text
import Hakyll
import Network.HTTP.Types.Status (status404)
import Network.Wai (Application, responseFile)
import Network.Wai.Application.Static qualified as Static
import System.FilePath (takeExtension)
import WaiAppStatic.Types
import Web.Site.Rules (rules)

-- | Configuration for Hakyll to generate the web site.
config :: Configuration
config :: Configuration
config =
  Configuration
defaultConfiguration
    { providerDirectory = "site",
      checkHtmlFile = hasExtension,
      deployCommand =
        unwords
          [ "rsync",
            "--checksum",
            "--compress",
            "--delete",
            "--exclude .well-known",
            "--links",
            "--recursive",
            "--verbose",
            "_site/",
            "chungyc@chungyc.org:chungyc.org/"
          ],
      previewSettings = serverSettings
    }

-- | Whether a file name has an extension.
hasExtension :: FilePath -> Bool
hasExtension :: String -> Bool
hasExtension String
path
  | String
"" <- String
extension = Bool
True
  | String
"html" <- String
extension = Bool
True
  | Bool
otherwise = Bool
False
  where
    extension :: String
extension = String -> String
takeExtension String
path

-- | Server customizations which fit better with this web site.
serverSettings :: FilePath -> Static.StaticSettings
serverSettings :: String -> StaticSettings
serverSettings String
path =
  StaticSettings
baseSettings
    { -- Allow HTML files to lack an extension.
      ssGetMimeType = getMimeType,
      -- Prevent browsers from caching files which may have changed for too long.
      ssMaxAge = MaxAgeSeconds 10,
      -- A 404 page consistent with the rest of the site is much better.
      ss404Handler = Just missing
    }
  where
    baseSettings :: StaticSettings
baseSettings = String -> StaticSettings
Static.defaultFileServerSettings String
path
    defaultGetMimeType :: File -> IO MimeType
defaultGetMimeType = StaticSettings -> File -> IO MimeType
ssGetMimeType StaticSettings
baseSettings

    -- Overrides MIME type for files with no extension
    -- so that HTML pages need no extension.
    getMimeType :: File -> IO MimeType
getMimeType File
file =
      if Char -> Text -> Bool
Text.elem Char
'.' (Piece -> Text
fromPiece (Piece -> Text) -> Piece -> Text
forall a b. (a -> b) -> a -> b
$ File -> Piece
fileName File
file)
        then File -> IO MimeType
defaultGetMimeType File
file
        else MimeType -> IO MimeType
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return MimeType
"text/html"

-- | Response handler for when missing resources are requested.
missing :: Application
missing :: Application
missing Request
_ Response -> IO ResponseReceived
respond = Response -> IO ResponseReceived
respond (Response -> IO ResponseReceived)
-> Response -> IO ResponseReceived
forall a b. (a -> b) -> a -> b
$ Status -> ResponseHeaders -> String -> Maybe FilePart -> Response
responseFile Status
status404 ResponseHeaders
headers String
file Maybe FilePart
forall a. Maybe a
Nothing
  where
    headers :: ResponseHeaders
headers = [(HeaderName
"Content-Type", MimeType
"text/html")]
    file :: String
file = String
"_site/server/errors/missing.html"