ema-0.2.0.0: src/Ema/Helper/Tailwind.hs
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeApplications #-}
-- | Use Tailwind CSS with blaze-html? Try this module for rapid prototyping of
-- websites in Ema.
module Ema.Helper.Tailwind
( -- * Main functions
layout,
layoutWith,
-- * Tailwind shims
twindShim,
twindShimCdn,
twindShimOfficial,
twindShimUnofficial,
)
where
import qualified Ema.CLI
import NeatInterpolation (text)
import qualified Text.Blaze.Html.Renderer.Utf8 as RU
import Text.Blaze.Html5 ((!))
import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A
-- | A simple and off-the-shelf layout using Tailwind CSS
layout :: Ema.CLI.Action -> H.Html -> H.Html -> LByteString
layout action =
layoutWith "en" "UTF-8" $ twindShim action
twindShim :: Ema.CLI.Action -> H.Html
twindShim action =
case action of
Ema.CLI.Generate _ ->
twindShimUnofficial
_ ->
-- Twind shim doesn't reliably work in dev server mode. Let's just use the
-- tailwind CDN.
twindShimCdn
-- | Like @layout@, but pick your own language, encoding and tailwind shim.
layoutWith :: H.AttributeValue -> H.AttributeValue -> H.Html -> H.Html -> H.Html -> LByteString
layoutWith lang encoding tshim appHead appBody = RU.renderHtml $ do
H.docType
H.html ! A.lang lang $ do
H.head $ do
H.meta ! A.charset encoding
-- This makes the site mobile friendly by default.
H.meta ! A.name "viewport" ! A.content "width=device-width, initial-scale=1"
tshim
appHead
-- The "overflow-y-scroll" makes the scrollbar visible always, so as to
-- avoid janky shifts when switching to routes with suddenly scrollable content.
H.body ! A.class_ "overflow-y-scroll" $ do
appBody
-- | Loads full tailwind CSS from CDN (not good for production)
twindShimCdn :: H.Html
twindShimCdn =
H.link
! A.href "https://unpkg.com/tailwindcss@latest/dist/tailwind.min.css"
! A.rel "stylesheet"
! A.type_ "text/css"
-- | This shim may not work with hot reload.
twindShimOfficial :: H.Html
twindShimOfficial =
H.unsafeByteString . encodeUtf8 $
[text|
<script type="module" src="https://cdn.skypack.dev/twind/shim"></script>
|]
-- | This shim does work with hot reload, but it spams console with warnings.
twindShimUnofficial :: H.Html
twindShimUnofficial = do
H.script
! A.type_ "text/javascript"
! A.src "https://cdn.jsdelivr.net/combine/npm/twind/twind.umd.min.js,npm/twind/observe/observe.umd.min.js"
$ ""
H.script ! A.type_ "text/javascript" $ twindShimUnofficialEval
where
twindShimUnofficialEval :: H.Html
twindShimUnofficialEval =
H.unsafeByteString . encodeUtf8 $
[text|
// Be silent to avoid complaining about non-tailwind classes
// https://github.com/tw-in-js/twind/discussions/180#discussioncomment-678272
console.log("ema: Twind: setup & observe")
twind.setup({mode: 'silent'})
window.emaTwindObs = twindObserve.observe(document.documentElement);
|]