{-# LANGUAGE OverloadedLists #-} {-# OPTIONS_GHC -Wno-orphans #-} module Worksheets.Utils.HTML ( module Worksheets.Utils.HTML, module Text.Blaze.Html5, module Text.Blaze.Renderer.Utf8, ) where import Data.Char qualified as Char import Data.List qualified as List import Data.Map.Strict qualified as Map import Data.Text qualified as Text import Data.Text.Short qualified as ShortText import Text.Blaze import Text.Blaze.Html5 import Text.Blaze.Html5.Attributes qualified as HA import Text.Blaze.Renderer.Utf8 import Worksheets.Utils.Paper import Worksheets.Utils.Prelude classes :: [String] -> Attribute classes cls = HA.class_ $ cls & List.filter (not . null) <&> toValue & List.intersperse " " & mconcat className :: Show a => a -> String className x = x & show & List.map \c -> if Char.isAlphaNum c then c else '-' type CSSBlock = Map String String styles :: CSSBlock -> Attribute styles kvs = HA.style $ [ toValue k <> ":" <> toValue v <> ";" | (k, v) <- kvs & Map.toList , not (null v) ] & mconcat type CSS = Map [String] CSSBlock styleCSS :: CSS -> Markup styleCSS m = style ! HA.type_ "text/css" $ [ mconcat [n <> " {" | n <- ns] <> "\n" <> List.unlines [ k <> ":" <> v <> ";" | (k, v) <- kvs & Map.toList , not (null v) ] <> mconcat [" }" | _n <- ns] <> "\n" | (ns, kvs) <- m & Map.toList , kvs & null & not ] & List.unlines & toHtml class ToCSS a where toCSS :: a -> String instance ToMarkup ShortText where toMarkup = ShortText.toText >>> toMarkup preEscapedToMarkup = ShortText.toText >>> preEscapedToMarkup data Length = LengthFractionalRatio Natural | LengthMillimeters Double deriving (Eq, Show) instance ToCSS Text where toCSS = Text.unpack instance ToCSS Length where toCSS = \case LengthFractionalRatio x -> show x <> "fr" LengthMillimeters x -> show x <> "mm" cm :: Double -> Length cm = LengthMillimeters . (* 10) mm :: Double -> Length mm = LengthMillimeters fr :: Natural -> Length fr = LengthFractionalRatio cssPageWidth = \case PageOrientationLandscape -> 29.7 & cm PageOrientationPortrait -> 21.0 & cm cssPageHeight = \case PageOrientationLandscape -> 21.0 & cm PageOrientationPortrait -> 29.7 & cm cssPageSize = \case PageSizeA5 -> "A5" PageSizeA4 -> "A4" PageSizeA4Plus -> "A4plus" PageSizeA3 -> "A3" cssPageOrientation = \case PageOrientationPortrait -> "portrait" PageOrientationLandscape -> "landscape" cssPrintPage :: PageOrientation -> PageSize -> CSS cssPrintPage pageOrient pageSize = [ [ ["@page"] := [ "size" := List.unwords [ cssPageSize pageSize , cssPageOrientation pageOrient ] ] ] ] & mconcat cssBlockObjectFitCover :: CSSBlock cssBlockObjectFitCover = ["object-fit" := "cover"]