1 {-# LANGUAGE OverloadedLists #-}
2 {-# LANGUAGE UndecidableInstances #-}
3 {-# OPTIONS_GHC -Wno-orphans #-}
5 module Literate.Document.HTML (
6 module Literate.Document.HTML,
7 module Text.Blaze.Html5,
8 module Text.Blaze.Renderer.Utf8,
12 import Data.Char qualified as Char
13 import Data.List qualified as List
14 import Data.Map.Strict qualified as Map
15 import Data.Text qualified as Text
16 import Data.Text.Short qualified as ShortText
17 import Literate.Document qualified as Doc
18 import Literate.Document.Table
19 import Literate.Document.Type hiding (classes, div)
20 import Literate.Prelude
22 import Text.Blaze.Html5
23 import Text.Blaze.Html5.Attributes qualified as HA
24 import Text.Blaze.Renderer.Utf8
26 instance IsString AttributeValue
27 instance IsString Html
29 classes :: [Class] -> Attribute
33 & List.filter (not . Text.null . Doc.unClass)
35 & List.intersperse " "
38 className :: Show a => a -> String
40 x & show & List.map \c ->
45 type CSSBlock = Map String String
47 styles :: CSSBlock -> Attribute
50 [ toValue k <> ":" <> toValue v <> ";"
51 | (k, v) <- kvs & Map.toList
56 type CSS = Map [String] CSSBlock
57 styleCSS :: CSS -> Markup
61 $ [ mconcat [n <> " {" | n <- ns]
64 [ k <> ":" <> v <> ";"
65 | (k, v) <- kvs & Map.toList
68 <> mconcat [" }" | _n <- ns]
70 | (ns, kvs) <- m & Map.toList
79 instance ToMarkup ShortText where
80 toMarkup = ShortText.toText >>> toMarkup
81 preEscapedToMarkup = ShortText.toText >>> preEscapedToMarkup
83 instance ToCSS Text where
86 instance ToCSS Length where
88 LengthAbsolute x -> x & toCSS
89 LengthRelative x -> x & toCSS
90 instance ToCSS LengthAbsolute where
92 LengthAbsoluteMillimeters x -> show x <> "mm"
93 instance ToCSS LengthRelative where
95 LengthRelativeFractionalRatio x -> show x <> "fr"
96 LengthRelativeMaxContent -> "max-content"
97 LengthRelativeMinContent -> "min-content"
100 PageOrientationLandscape -> 29.7 & cm
101 PageOrientationPortrait -> 21.0 & cm
102 cssPageHeight = \case
103 PageOrientationLandscape -> 21.0 & cm
104 PageOrientationPortrait -> 29.7 & cm
108 PageSizeA4Plus -> "A4plus"
110 cssPageOrientation = \case
111 PageOrientationPortrait -> "portrait"
112 PageOrientationLandscape -> "landscape"
114 cssPrintPage :: PageOrientation -> PageSize -> CSS
115 cssPrintPage pageOrient pageSize =
120 [ cssPageSize pageSize
121 , cssPageOrientation pageOrient
128 cssBlockObjectFitCover :: CSSBlock
129 cssBlockObjectFitCover = ["object-fit" := "cover"]
131 instance ToMarkup Block where
133 BlockDiv x -> x & toMarkup
134 BlockFlex x -> x & toMarkup
135 BlockList x -> x & toMarkup
136 BlockPara x -> p $ x & toMarkup
137 BlockTable x -> x & toMarkup
138 BlockDict x -> x & toMarkup
139 Blocks xs -> xs & foldMap toMarkup
140 instance ToMarkup Inline where
142 InlineText x -> x & toMarkup
143 InlineCode x -> code $ x & toMarkup
144 InlineLink{inlineLinkText, inlineLinkTarget} ->
145 a ! HA.href (inlineLinkTarget & unTarget & toValue) $ inlineLinkText & toMarkup
146 Inlines xs -> xs & foldMap toMarkup
147 instance ToMarkup FlexItem where
149 forM_ (itm & flexItemContent) toMarkup
150 instance ToMarkup Div where
153 { divAnchor = maybeId
157 (maybe div (\anchor -> div ! HA.id (anchor & toValue)) maybeId) ! classes cls $
159 instance ToMarkup Flex where
163 [ "display" := "flex"
164 , "flex-direction" := flx & flexDirection & toCSS
165 , "gap" := flx & flexGap & toCSS
168 forM_ (flx & flexItems) toMarkup
170 instance ToMarkup List where
171 toMarkup List{listItems} =
175 [ "grid-template-columns" :=
176 [ LengthRelative LengthRelativeMaxContent
177 , LengthRelative $ 1 & fr
183 forM_ (listItems & ol1) \(itemCount, (itemKey, itemValue)) -> do
184 div ! classes ["list-body", if even itemCount then "even" else "odd"] $ do
186 ! classes ["list-key"]
187 ! styles ["justify-items" := JustificationRight & toCSS]
191 ! classes ["list-value"]
192 ! styles ["justify-items" := JustificationLeft & toCSS]
195 instance ToMarkup Table where
199 ! styles ["grid-template-columns" := tbl & tableTemplateFinal <&> toCSS & List.unwords]
201 forM_ (tbl & tableHeads) \hd -> do
202 div ! classes ["table-head"] $ do
203 forM_ (hd & tableHeadColumns) \cel -> do
204 div ! classes ["table-cell"] $ do
206 cel & tableCellContent & toMarkup
207 forM_ (tbl & tableRows & ol1) \(rowCount, row) -> do
208 div ! classes ["table-body", if even rowCount then "even" else "odd"] $ do
209 forM_ (row & tableRowColumns) \cel -> do
211 ! classes ["table-cell"]
212 ! styles ["justify-items" := cel & tableCellJustify & toCSS]
214 cel & tableCellContent & toMarkup
215 instance ToMarkup Dict where
220 forM_ (dic & dictEntries) \(key, val) ->
221 div ! classes ["dict-entry"] $ do
222 div ! classes ["dict-key"] $ do
225 div ! classes ["dict-value"] $ do
227 instance ToCSS Justification where
229 JustificationLeft -> "left"
230 JustificationBegin -> "begin"
231 JustificationCenter -> "center"
232 JustificationEnd -> "end"
233 JustificationRight -> "right"
234 instance ToCSS FlexDirection where
236 FlexDirectionColumn -> "column"
237 FlexDirectionRow -> "row"