3 import Data.List qualified as List
4 import Data.Map.Strict qualified as Map
5 import Data.Text qualified as Text
6 import Data.Time qualified as Time
9 import Network.URI.Slug (decodeSlug, encodeSlug)
12 import Text.Blaze qualified as B
13 import Text.Blaze.Html5 ((!))
14 import Text.Blaze.Html5 qualified as H
15 import Text.Blaze.Html5.Attributes qualified as A
21 renderBody :: Model -> Route -> Content -> H.Html
22 renderBody model@Model{..} route Content{..} =
23 -- The "overflow-y-scroll" makes the scrollbar visible always, so as to
24 -- avoid content shifts when switching to routes with suddenly scrollable content.
40 --renderNav model route
55 | Just{} <- Map.lookup page modelPosts ->
58 | Just{} <- Map.lookup page modelSpecials ->
60 RouteFilter filt@Filter{..}
61 | maybe True (`elem` allTagsModel) filterTag ->
62 html $ "list" : encodeFilter filt
63 RouteFeeds -> html ["feeds"]
64 RouteFilterAtom filt@Filter{..}
65 | maybe True (`elem` allTagsModel) filterTag ->
66 html $ "feed" : encodeFilter filt
68 --error [fmt|Route {notFound:s} does not exist.|]
71 allTagsModel = allTags model
83 [ H.li ! classes (if path == [] then ["pr-2"] else ["px-2"]) $
84 H.a ! A.href (B.toValue $ encodeSlugs path) $
85 H.text $ encodeSlug slug
88 (decodeSlug (Text.toLower orgName) : slugs)
105 ! classes ["hover:bg-blue-100", "text-blue-600"]
106 ! A.href [fmt|{Ema.routeUrl model $ Right @FilePath route:s}#top|]
110 ! classes ["text-gray-600"]
111 $ [fmt|Generated: {maybe "dynamically"
112 (Time.formatTime Time.defaultTimeLocale "%F")
118 ! A.href [fmt|https://git.code.{domainName}/~julm/sourcephile-web|]
119 $ "code for this site"
122 ! A.href "https://spdx.org/licenses/AGPL-3.0-or-later.html"
123 $ "AGPL-3.0-or-later"
127 renderNav :: Model -> Route -> H.Html
128 renderNav model route =
129 H.div ! A.id "top" ! classes ["bg-gray-500"] $
139 , "sm:justify-between"
155 -- ! classes ["w-10", "h-10", "mr-4", "rounded-full"]
156 -- ! A.src "/static/img/my_avatar.jpg"
160 , (hrefRoute model $ RouteFilter noFilter, "All Posts")
161 , (hrefRoute model $ RouteFilter noFilter{filterTag = Just $ Tag "non-tech"}, "Non-Tech")
162 , (hrefRoute model $ RouteFilter noFilter{filterTag = Just $ Tag "tech"}, "Tech")
163 , (hrefRoute model $ RouteSpecial ["projects"], "Projects")
165 H.span ! classes ["flex", "flex-row", "justify-items-center"] $
167 [ (A.title "Atom" <> hrefRoute model RouteFeeds, openIconic "rss")
168 , (A.title "IRC" <> A.href [fmt|irc://irc.geeknode.org/#sourcephile|], openIconic "chat")
169 , (A.title "XMPP" <> A.href [fmt|xmpp:sourcephile@{domainName}?join|], openIconic "chat")
170 , (A.title "Mail" <> A.href [fmt|mailto:contact@{domainName}|], openIconic "envelope-closed")
171 , (A.title "Git" <> A.href [fmt|https://git.code.{domainName}|], openIconic "fork")
174 headLinks = mapM_ $ \(attrs, html) ->
179 , "hover:bg-blue-600"
182 , "justify-items-center"
189 ! A.style "font-variant: small-caps"
191 $ html ! classes ["w-4"]