clay-0.16.1: src/Clay/Geometry.hs
{-# LANGUAGE OverloadedStrings #-}
module Clay.Geometry
(
-- * Positioning.
size, top, left, bottom, right
-- * Sizing.
, width, height, minWidth, minHeight, maxWidth, maxHeight
-- ** Aspect ratio.
, AspectRatio
, aspectRatio
, (%)
, withFallback
-- * Padding.
, padding
, paddingTop, paddingLeft, paddingRight, paddingBottom
-- * Margin.
, margin
, marginTop, marginLeft, marginRight, marginBottom
)
where
import qualified Data.Ratio as R
import Data.String (fromString)
import Clay.Common
import Clay.Property
import Clay.Stylesheet
import Clay.Size
-------------------------------------------------------------------------------
size, top, left, bottom, right :: Size a -> Css
size = key "size"
top = key "top"
left = key "left"
bottom = key "bottom"
right = key "right"
width, height, minWidth, minHeight, maxWidth, maxHeight :: Size a -> Css
width = key "width"
height = key "height"
minWidth = key "min-width"
minHeight = key "min-height"
maxWidth = key "max-width"
maxHeight = key "max-height"
-------------------------------------------------------------------------------
-- | Represents an aspect ratio for use with 'aspectRatio'.
--
-- A fixed ratio can be formed from two integers:
--
-- >>> let _ = 4%3 :: AspectRatio
--
-- An aspect ratio can also be converted from a 'Rational':
--
-- >>> let _ = fromRational 0.5 :: AspectRatio
--
data AspectRatio = AspectRatio Rational
| AspectRatioValue Value
| AspectRatioWithFallback (AspectRatio, AspectRatio)
instance Auto AspectRatio where auto = AspectRatioValue auto
instance Inherit AspectRatio where inherit = AspectRatioValue inherit
instance Initial AspectRatio where initial = AspectRatioValue initial
instance Unset AspectRatio where unset = AspectRatioValue unset
instance Other AspectRatio where other = AspectRatioValue
-- | An 'AspectRatio' can be converted from an 'Integer',
-- but other operations are not supported.
instance Num AspectRatio where
fromInteger = AspectRatio . toRational
(+) = error "plus not implemented for AspectRatio"
(*) = error "times not implemented for AspectRatio"
abs = error "abs not implemented for AspectRatio"
signum = error "signum not implemented for AspectRatio"
negate = error "negate not implemented for AspectRatio"
-- | An 'AspectRatio' can be converted from a 'Rational',
-- but other operations are not supported.
instance Fractional AspectRatio where
fromRational = AspectRatio
recip = error "recip not implemented for AspectRatio"
instance Val AspectRatio where
value (AspectRatioValue v) = v
value (AspectRatio r) = v
where v = fromString $ numerator <> "/" <> denominator :: Value
numerator = show (R.numerator r)
denominator = show (R.denominator r)
value (AspectRatioWithFallback (a, b)) = value a <> " " <> value b
-- | Defines the width to height ratio of an element.
-- At least one of the width or height must be of automatic size,
-- otherwise the aspect ratio will be ignored.
--
-- It can be given a fixed ratio of the width to the height:
--
-- >>> renderWith compact [] $ aspectRatio (4%3)
-- "{aspect-ratio:4/3}"
--
-- It can also be the intrinsic aspect ratio for the element:
--
-- >>> renderWith compact [] $ aspectRatio auto
-- "{aspect-ratio:auto}"
--
-- It can be told to use the intrinsic aspect ratio for the element,
-- but to use a fixed ratio while it is unknown or if the element does not have one:
--
-- >>> renderWith compact [] $ aspectRatio $ auto `withFallback` (4%3)
-- "{aspect-ratio:auto 4/3}"
--
-- Corresponds to the
-- [@aspect-ratio@](https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio)
-- property in CSS.
aspectRatio :: AspectRatio -> Css
aspectRatio = key "aspect-ratio"
-- | The aspect ratio of the width to the height for use with 'aspectRatio'.
--
-- Note that this is /not/ the same @%@ operator from the "Data.Ratio" module,
-- although they do both semantically represent ratios. The same symbol is used
-- to signify that the return value is a ratio.
(%) :: Integer -> Integer -> AspectRatio
(%) m n = fromRational $ (R.%) m n
-- The same as the normal % operator.
infixl 7 %
-- | Returns an aspect ratio specifying that the intrinsic aspect
-- ratio should be used, but when it is unknown or there is none,
-- a fixed ratio can be used as a fallback.
withFallback :: AspectRatio -> AspectRatio -> AspectRatio
withFallback x@(AspectRatioValue "auto") y@(AspectRatio _) =
AspectRatioWithFallback (x, y)
withFallback x@(AspectRatio _) y@(AspectRatioValue "auto") =
AspectRatioWithFallback (x, y)
withFallback _ _ =
error "Arguments for aspectRatio . withFallback must be auto and a ratio in either order"
-------------------------------------------------------------------------------
padding :: Size a -> Size a -> Size a -> Size a -> Css
padding a b c d = key "padding" (a ! b ! c ! d)
paddingTop, paddingLeft, paddingRight, paddingBottom :: Size a -> Css
paddingTop = key "padding-top"
paddingLeft = key "padding-left"
paddingRight = key "padding-right"
paddingBottom = key "padding-bottom"
-------------------------------------------------------------------------------
margin :: Size a -> Size a -> Size a -> Size a -> Css
margin a b c d = key "margin" (a ! b ! c ! d)
marginTop, marginLeft, marginRight, marginBottom :: Size a -> Css
marginTop = key "margin-top"
marginLeft = key "margin-left"
marginRight = key "margin-right"
marginBottom = key "margin-bottom"