import Control.Monad (void)
 import Control.Monad.Error.Class (MonadError(..))
 import Control.Monad.IO.Class (MonadIO(..), liftIO)
+import Data.Bifunctor (first)
 import Data.ByteString.Lazy (ByteString(..))
-import Data.List (sort)
+import Data.List (sortOn)
 import Data.Maybe (fromMaybe)
+import Data.Time.Clock (UTCTime(..))
+import Data.Time.Format (formatTime, defaultTimeLocale, iso8601DateFormat)
 import Lucid
 import Sanitize
 import Servant
-import System.Directory (getDirectoryContents)
+import System.Directory (getDirectoryContents, getModificationTime)
+import System.FilePath.Posix ((</>))
 import qualified Data.Text as T
 import qualified Data.Text.IO as T
 
     blogListItems
 
 blogList :: (MonadIO m) => Maybe Theme -> m (Html ())
-blogList theme = liftIO $ getDirectoryContents staticPath >>= pure . foldMap (blogListItem theme) . sort . filter (T.isSuffixOf markdownExtension) . fmap T.pack
+blogList theme = liftIO $ getDirectoryContents staticPath >>= mapM blogModificationTime . fmap T.unpack . filter (T.isSuffixOf markdownExtension) . fmap T.pack >>= pure . foldMap (blogListItem theme) . sortOn snd . fmap (first T.pack)
 
-blogListItem :: Maybe Theme -> T.Text -> Html ()
-blogListItem theme (blogLink -> Nothing) = pure $ mempty
-blogListItem theme (blogLink -> (Just file)) = li_ [class_ "blog-link"] $ a_ [href_ $ safeBlogLink theme $ T.unpack file] $ toHtml file
+blogModificationTime :: (MonadIO m) => FilePath -> m (FilePath, UTCTime)
+blogModificationTime filePath = liftIO $ getModificationTime (staticPath </> filePath) >>= pure . (,) filePath
+
+blogListItem :: Maybe Theme -> (T.Text, UTCTime) -> Html ()
+blogListItem theme (first blogLink -> (Nothing, _)) = pure $ mempty
+blogListItem theme (first blogLink -> (Just file, time)) = li_ [class_ "blog-link"] $ a_ [href_ $ safeBlogLink theme $ T.unpack file] $ toHtml $ blogNameWithDate file time
+
+blogNameWithDate :: T.Text -> UTCTime -> T.Text
+blogNameWithDate file time = file <> " (last modified: " <> T.pack (formatTime defaultTimeLocale (iso8601DateFormat Nothing) $ utctDay time) <> ")"
 
 blogLink :: T.Text -> Maybe T.Text
 blogLink = T.stripSuffix markdownExtension
 siteTitle = "Saba's Site"
 
 staticPath :: FilePath
-staticPath = "static/"
+staticPath = "static"
 
 imagePath :: FilePath
-imagePath = staticPath <> "img/"
+imagePath = staticPath </> "img"
 
 markdownExtension :: T.Text
 markdownExtension = ".md"
 
 import RenderBlog (renderBlog)
 import Servant
 import StyleSheet
+import System.FilePath.Posix ((</>))
 import qualified Clay as C
 import qualified Data.ByteString.Lazy as B
 import qualified Data.Text as T
 blogPost theme blogId = handleAny (blogNotFound theme blogId) $ findBlogPost blogId >>= htmlContainer theme (Just blogId) . renderBlog
 
 findBlogPost :: BlogId -> Handler T.Text
-findBlogPost = liftIO . T.readFile . (<>) staticPath . flip (<>) (T.unpack markdownExtension)
+findBlogPost = liftIO . T.readFile . (</>) staticPath . flip (<>) (T.unpack markdownExtension)
 
 changeTheme :: Theme -> BlogId -> Handler (Html ())
 changeTheme theme = blogPost (Just theme)
 
 imageLink :: ImageId -> Handler B.ByteString
-imageLink imageId = handleAny imageNotFound $ liftIO $ B.readFile $ imagePath <> imageId
+imageLink imageId = handleAny imageNotFound $ liftIO $ B.readFile $ imagePath </> imageId
 
 styling :: Maybe Theme -> Handler C.Css
 styling (fromMaybe defaultTheme -> theme) = pure $ getStyleFromTheme (themeType theme) $ C.rgba (themeRed theme) (themeGreen theme) (themeBlue theme) 1