packages feed

atomic-css-0.1.0: src/Web/Atomic/Types/ClassName.hs

module Web.Atomic.Types.ClassName where

import Data.String (IsString (..))
import Data.Text (Text, pack)
import Data.Text qualified as T


-- | A class name
newtype ClassName = ClassName
  { text :: Text
  }
  deriving newtype (Eq, Ord, Show, Monoid, Semigroup)


instance IsString ClassName where
  fromString = className . pack


-- | Create a class name, escaping special characters
className :: Text -> ClassName
className = ClassName . T.toLower . T.map noDot
 where
  noDot '.' = '-'
  noDot c = c


-- | Convert a type into a className segment to generate unique compound style names based on the value
class ToClassName a where
  toClassName :: a -> ClassName
  default toClassName :: (Show a) => a -> ClassName
  toClassName = className . pack . show


instance ToClassName Int
instance ToClassName Text where
  toClassName = className
instance ToClassName Float where
  toClassName f = ClassName $ "p" <> pack (show $ round @Float @Int (f * 100))
instance ToClassName ClassName where
  toClassName = id
instance ToClassName [ClassName] where
  toClassName cs = ClassName $ T.intercalate "-" $ fmap (.text) cs
instance ToClassName () where
  toClassName _ = ""


-- | Hyphenate classnames
(-.) :: (ToClassName a) => ClassName -> a -> ClassName
cn -. a = joinClassSegments "-" cn (toClassName a)


infixl 7 -.


joinClassSegments :: Text -> ClassName -> ClassName -> ClassName
joinClassSegments _ "" cn = cn
joinClassSegments _ cn "" = cn
joinClassSegments sep (ClassName cn1) (ClassName cn2) =
  ClassName $ cn1 <> sep <> cn2


-- modifiers to a class are prepended with ":", like hover\:my-class:hover
addClassState :: (ToClassName a) => a -> ClassName -> ClassName
addClassState a = joinClassSegments ":" (toClassName a)


-- appendClassSegments :: (ToClassName a) => [a] -> ClassName -> ClassName
-- appendClassSegments as cn = foldl (flip appendClassSegment) cn as

classesAttValue :: [ClassName] -> Text
classesAttValue clss =
  T.unwords $ fmap (.text) clss