-- |
-- Description: Support generation of table of contents in programmatically generated pages on this website.
-- Copyright: Copyright (C) 2024 Yoo Chung
-- License: All rights reserved
-- Maintainer: web@chungyc.org
--
-- Support generation of table of contents in programmatically generated pages on this website.
-- This is for pages where the HTML is directly generated using Haskell code.
--
-- For example, the following generates HTML for a table of contents:
--
-- >>> import Text.Blaze.Html.Renderer.Pretty (renderHtml)
-- >>> :{
-- putStr $ renderHtml$ toc $
--   [ Entry "First section" "#first"
--     [ Entry "First sub-section" "#first-sub" []
--     , Entry "Second sub-section" "#second-sub" []
--     ]
--   , Entry "Second section" "#second" []
--   ]
-- :}
-- <nav class="toc">
--     <h2>
--         Contents
--     </h2>
--     <ul>
--         <li>
--             <a href="#first">
--                 First section
--             </a>
--             <ul>
--                 <li>
--                     <a href="#first-sub">
--                         First sub-section
--                     </a>
--                 </li>
--                 <li>
--                     <a href="#second-sub">
--                         Second sub-section
--                     </a>
--                 </li>
--             </ul>
--         </li>
--         <li>
--             <a href="#second">
--                 Second section
--             </a>
--         </li>
--     </ul>
-- </nav>
module Web.Generate.Contents (Entry (..), toc) where

import Control.Monad (unless)
import Text.Blaze.Html5
import Text.Blaze.Html5.Attributes

-- | An entry in the table of contents.
data Entry
  = Entry
      -- | Title of the section.
      Html
      -- | Anchor to the section.
      AttributeValue
      -- | Sub-entries under the section.
      [Entry]

-- | Generate HTML for the table of contents.
toc :: [Entry] -> Html
toc :: [Entry] -> Html
toc [Entry]
xs = Html -> Html
nav (Html -> Html) -> Attribute -> Html -> Html
forall h. Attributable h => h -> Attribute -> h
! AttributeValue -> Attribute
class_ AttributeValue
"toc" (Html -> Html) -> Html -> Html
forall a b. (a -> b) -> a -> b
$ do
  Html -> Html
h2 Html
"Contents"
  [Entry] -> Html
toList [Entry]
xs

-- | Generate an HTML list from a list of entries in a table of contents.
toList :: [Entry] -> Html
toList :: [Entry] -> Html
toList [Entry]
xs = Html -> Html
ul (Html -> Html) -> Html -> Html
forall a b. (a -> b) -> a -> b
$ (Entry -> Html) -> [Entry] -> Html
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Entry -> Html
fromEntry [Entry]
xs

-- | Generate the HTML for an entry in a table of contents.
fromEntry :: Entry -> Html
fromEntry :: Entry -> Html
fromEntry (Entry Html
title' AttributeValue
anchor [Entry]
subentries) = do
  Html -> Html
li (Html -> Html) -> Html -> Html
forall a b. (a -> b) -> a -> b
$ do
    Html -> Html
a (Html -> Html) -> Attribute -> Html -> Html
forall h. Attributable h => h -> Attribute -> h
! AttributeValue -> Attribute
href AttributeValue
anchor (Html -> Html) -> Html -> Html
forall a b. (a -> b) -> a -> b
$ Html
title'
    Bool -> Html -> Html
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([Entry] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Entry]
subentries) (Html -> Html) -> Html -> Html
forall a b. (a -> b) -> a -> b
$ [Entry] -> Html
toList [Entry]
subentries