{-|
Module: IHP.View.CSSFramework.Bootstrap
Description: Bootstrap CSS framework implementations
Copyright: (c) digitally induced GmbH, 2020
-}
module IHP.View.CSSFramework.Bootstrap (bootstrap, bootstrap4) where

import Prelude hiding (null)
import Data.Text (Text, null)
import Data.ByteString (ByteString)
import Data.Maybe (isJust)
import Data.Default (def)
import Control.Monad (unless)
import IHP.HaskellSupport (forEach)
import IHP.ModelSupport.Types (Violation(..))
import IHP.InputValue (inputValue)
import qualified Text.Blaze.Html5 as Blaze
import IHP.HSX.QQ (hsx)
import IHP.HSX.ToHtml ()
import IHP.View.Types
import IHP.View.Classes
import IHP.Breadcrumb.Types
import IHP.Pagination.Helpers
import IHP.Pagination.Types
import Network.Wai.Middleware.FlashMessages (FlashMessage (..))
import IHP.View.CSSFramework.Unstyled ()

bootstrap :: CSSFramework
bootstrap :: CSSFramework
bootstrap = CSSFramework
forall a. Default a => a
def
    { styledFlashMessage
    , styledSubmitButtonClass
    , styledFormGroupClass
    , styledFormFieldHelp
    , styledInputClass
    , styledInputInvalidClass
    , styledValidationResultClass
    }
    where
        styledFlashMessage :: p -> FlashMessage -> Html
styledFlashMessage p
_ (SuccessFlashMessage Text
message) = [hsx|<div class="alert alert-success">{message}</div>|]
        styledFlashMessage p
_ (ErrorFlashMessage Text
message) = [hsx|<div class="alert alert-danger">{message}</div>|]

        styledInputClass :: p -> FormField -> a
styledInputClass p
_ FormField { fieldType :: FormField -> InputType
fieldType = InputType
FileInput } = a
"form-control-file"
        styledInputClass p
_ FormField {} = a
"form-control"
        styledInputInvalidClass :: p -> p -> a
styledInputInvalidClass p
_ p
_ = a
"is-invalid"

        styledFormFieldHelp :: p -> FormField -> Html
styledFormFieldHelp p
_ FormField { helpText :: FormField -> Text
helpText = Text
"" } = Html
forall a. Monoid a => a
mempty
        styledFormFieldHelp p
_ FormField { Text
helpText :: FormField -> Text
helpText :: Text
helpText } = [hsx|<small class="form-text">{helpText}</small>|]

        styledFormGroupClass :: Text
styledFormGroupClass = Text
"mb-3"

        styledValidationResultClass :: Text
styledValidationResultClass = Text
"invalid-feedback"

        styledSubmitButtonClass :: Text
styledSubmitButtonClass = Text
"btn btn-primary"

bootstrap4 :: CSSFramework
bootstrap4 :: CSSFramework
bootstrap4 = CSSFramework
forall a. Default a => a
def
    { styledFlashMessage
    , styledFormField
    , styledTextFormField
    , styledTextareaFormField
    , styledCheckboxFormField
    , styledSelectFormField
    , styledFormGroup
    , styledSubmitButton
    , styledSubmitButtonClass
    , styledFormFieldHelp
    , styledInputClass
    , styledInputInvalidClass
    , styledFormGroupClass
    , styledValidationResult
    , styledValidationResultClass
    , styledPagination
    , styledPaginationPageLink
    , styledPaginationDotDot
    , styledPaginationItemsPerPageSelector
    , styledPaginationLinkPrevious
    , styledPaginationLinkNext
    , styledBreadcrumb
    , styledBreadcrumbItem
    }
    where
        styledFlashMessage :: p -> FlashMessage -> Html
styledFlashMessage p
_ (SuccessFlashMessage Text
message) = [hsx|<div class="alert alert-success">{message}</div>|]
        styledFlashMessage p
_ (ErrorFlashMessage Text
message) = [hsx|<div class="alert alert-danger">{message}</div>|]

        styledInputClass :: p -> FormField -> a
styledInputClass p
_ FormField { fieldType :: FormField -> InputType
fieldType = InputType
FileInput } = a
"form-control-file"
        styledInputClass p
_ FormField {} = a
"form-control"
        styledInputInvalidClass :: p -> p -> a
styledInputInvalidClass p
_ p
_ = a
"is-invalid"

        styledFormFieldHelp :: p -> FormField -> Html
styledFormFieldHelp p
_ FormField { helpText :: FormField -> Text
helpText = Text
"" } = Html
forall a. Monoid a => a
mempty
        styledFormFieldHelp p
_ FormField { Text
helpText :: FormField -> Text
helpText :: Text
helpText } = [hsx|<small class="form-text text-muted">{helpText}</small>|]

        styledFormGroupClass :: Text
styledFormGroupClass = Text
"form-group"

        styledValidationResultClass :: Text
styledValidationResultClass = Text
"invalid-feedback"

        styledSubmitButtonClass :: Text
styledSubmitButtonClass = Text
"btn btn-primary"


        styledFormField :: CSSFramework -> FormField -> Blaze.Html
        styledFormField :: CSSFramework -> FormField -> Html
styledFormField cssFramework :: CSSFramework
cssFramework@CSSFramework {CSSFramework -> FormField -> Html
styledValidationResult :: CSSFramework -> CSSFramework -> FormField -> Html
styledValidationResult :: CSSFramework -> FormField -> Html
styledValidationResult, CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField :: CSSFramework -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField :: CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField, CSSFramework -> FormField -> Html -> Html
styledCheckboxFormField :: CSSFramework -> CSSFramework -> FormField -> Html -> Html
styledCheckboxFormField :: CSSFramework -> FormField -> Html -> Html
styledCheckboxFormField, CSSFramework -> FormField -> Html -> Html
styledSelectFormField :: CSSFramework -> CSSFramework -> FormField -> Html -> Html
styledSelectFormField :: CSSFramework -> FormField -> Html -> Html
styledSelectFormField, CSSFramework -> FormField -> Html -> Html
styledRadioFormField :: CSSFramework -> FormField -> Html -> Html
styledRadioFormField :: CSSFramework -> CSSFramework -> FormField -> Html -> Html
styledRadioFormField, CSSFramework -> FormField -> Html -> Html
styledTextareaFormField :: CSSFramework -> CSSFramework -> FormField -> Html -> Html
styledTextareaFormField :: CSSFramework -> FormField -> Html -> Html
styledTextareaFormField} FormField
formField =
            Html -> Html
formGroup Html
renderInner
            where
                renderInner :: Html
renderInner = case FormField
formField.fieldType of
                    InputType
TextInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"text" FormField
formField Html
validationResult
                    InputType
NumberInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"number" FormField
formField Html
validationResult
                    InputType
PasswordInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"password" FormField
formField Html
validationResult
                    InputType
ColorInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"color" FormField
formField Html
validationResult
                    InputType
EmailInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"email" FormField
formField Html
validationResult
                    InputType
DateInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"date" FormField
formField Html
validationResult
                    InputType
DateTimeInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"datetime-local" FormField
formField Html
validationResult
                    InputType
UrlInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"url" FormField
formField Html
validationResult
                    InputType
CheckboxInput -> CSSFramework -> FormField -> Html -> Html
styledCheckboxFormField CSSFramework
cssFramework FormField
formField Html
validationResult
                    InputType
HiddenInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"hidden" FormField
formField { disableLabel = True, disableGroup = True, disableValidationResult = True } Html
validationResult
                    InputType
TextareaInput -> CSSFramework -> FormField -> Html -> Html
styledTextareaFormField CSSFramework
cssFramework FormField
formField Html
validationResult
                    SelectInput {} -> CSSFramework -> FormField -> Html -> Html
styledSelectFormField CSSFramework
cssFramework FormField
formField Html
validationResult
                    RadioInput {} -> CSSFramework -> FormField -> Html -> Html
styledRadioFormField CSSFramework
cssFramework FormField
formField Html
validationResult
                    InputType
FileInput -> CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField CSSFramework
cssFramework Text
"file" FormField
formField Html
validationResult

                validationResult :: Blaze.Html
                validationResult :: Html
validationResult = Bool -> Html -> Html
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless FormField
formField.disableValidationResult (CSSFramework -> FormField -> Html
styledValidationResult CSSFramework
cssFramework FormField
formField)

                -- | Wraps the input inside a @<div class="form-group">...</div>@ (unless @disableGroup = True@)
                formGroup :: Blaze.Html -> Blaze.Html
                formGroup :: Html -> Html
formGroup Html
renderInner = case FormField
formField of
                    FormField { disableGroup :: FormField -> Bool
disableGroup = Bool
True } -> Html
renderInner
                    FormField { Text
fieldInputId :: Text
fieldInputId :: FormField -> Text
fieldInputId } -> CSSFramework -> Text -> Html -> Html
styledFormGroup CSSFramework
cssFramework Text
fieldInputId Html
renderInner


        styledFormGroup :: CSSFramework -> Text -> Blaze.Html -> Blaze.Html
        styledFormGroup :: CSSFramework -> Text -> Html -> Html
styledFormGroup cssFramework :: CSSFramework
cssFramework@CSSFramework {Text
styledFormGroupClass :: CSSFramework -> Text
styledFormGroupClass :: Text
styledFormGroupClass} Text
fieldInputId Html
renderInner =
            [hsx|<div class={styledFormGroupClass} id={"form-group-" <> fieldInputId}>{renderInner}</div>|]

        styledCheckboxFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledCheckboxFormField :: CSSFramework -> FormField -> Html -> Html
styledCheckboxFormField cssFramework :: CSSFramework
cssFramework@CSSFramework {CSSFramework -> FormField -> Text
styledInputInvalidClass :: CSSFramework -> CSSFramework -> FormField -> Text
styledInputInvalidClass :: CSSFramework -> FormField -> Text
styledInputInvalidClass, CSSFramework -> FormField -> Html
styledFormFieldHelp :: CSSFramework -> CSSFramework -> FormField -> Html
styledFormFieldHelp :: CSSFramework -> FormField -> Html
styledFormFieldHelp} formField :: FormField
formField@FormField {InputType
fieldType :: FormField -> InputType
fieldType :: InputType
fieldType, Text
fieldName :: Text
fieldName :: FormField -> Text
fieldName, Text
fieldLabel :: Text
fieldLabel :: FormField -> Text
fieldLabel, Text
fieldValue :: Text
fieldValue :: FormField -> Text
fieldValue, Text
fieldInputId :: FormField -> Text
fieldInputId :: Text
fieldInputId, Maybe Violation
validatorResult :: Maybe Violation
validatorResult :: FormField -> Maybe Violation
validatorResult, Text
fieldClass :: Text
fieldClass :: FormField -> Text
fieldClass, Bool
disabled :: Bool
disabled :: FormField -> Bool
disabled, Bool
disableLabel :: FormField -> Bool
disableLabel :: Bool
disableLabel, Bool
disableValidationResult :: FormField -> Bool
disableValidationResult :: Bool
disableValidationResult, [(Text, Text)]
additionalAttributes :: [(Text, Text)]
additionalAttributes :: FormField -> [(Text, Text)]
additionalAttributes, Text
labelClass :: Text
labelClass :: FormField -> Text
labelClass, Bool
required :: Bool
required :: FormField -> Bool
required, Bool
autofocus :: Bool
autofocus :: FormField -> Bool
autofocus } Html
validationResult = do
            [hsx|<div class="form-check">{element}</div>|]
            where
                inputInvalidClass :: Text
inputInvalidClass = CSSFramework -> FormField -> Text
styledInputInvalidClass CSSFramework
cssFramework FormField
formField
                helpText :: Html
helpText = CSSFramework -> FormField -> Html
styledFormFieldHelp CSSFramework
cssFramework FormField
formField

                -- If the checkbox is checked off, the browser will not send the parameter as part of the form.
                -- This will then make it impossible to set a field to False using a checkbox.
                -- For that we add the "hidden" input type.
                theInput :: Html
theInput = [hsx|
                                <input
                                    type="checkbox"
                                    name={fieldName}
                                    class={classes ["form-check-input", (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                                    id={fieldInputId}
                                    checked={fieldValue == "yes"}
                                    required={required}
                                    disabled={disabled}
                                    autofocus={autofocus}
                                    {...additionalAttributes}
                                />

                                <input type="hidden" name={fieldName} value={inputValue False} />
                        |]


                element :: Html
element = if Bool
disableLabel
                    then [hsx|<div>
                                {theInput}
                                {validationResult}
                                {helpText}
                            </div>
                        |]
                    else [hsx|
                            {theInput}
                            <label
                                class={classes [("form-check-label", labelClass == ""), (labelClass, labelClass /= "")]}
                                for={fieldInputId}
                            >
                                {fieldLabel}
                            </label>

                            {validationResult}
                            {helpText}
                        |]

        styledTextFormField :: CSSFramework -> Text -> FormField -> Blaze.Html -> Blaze.Html
        styledTextFormField :: CSSFramework -> Text -> FormField -> Html -> Html
styledTextFormField cssFramework :: CSSFramework
cssFramework@CSSFramework {CSSFramework -> FormField -> Text
styledInputClass :: CSSFramework -> CSSFramework -> FormField -> Text
styledInputClass :: CSSFramework -> FormField -> Text
styledInputClass, CSSFramework -> FormField -> Text
styledInputInvalidClass :: CSSFramework -> CSSFramework -> FormField -> Text
styledInputInvalidClass :: CSSFramework -> FormField -> Text
styledInputInvalidClass, CSSFramework -> FormField -> Html
styledFormFieldHelp :: CSSFramework -> CSSFramework -> FormField -> Html
styledFormFieldHelp :: CSSFramework -> FormField -> Html
styledFormFieldHelp} Text
inputType formField :: FormField
formField@FormField {InputType
fieldType :: FormField -> InputType
fieldType :: InputType
fieldType, Text
fieldName :: FormField -> Text
fieldName :: Text
fieldName, Text
fieldLabel :: FormField -> Text
fieldLabel :: Text
fieldLabel, Text
fieldValue :: FormField -> Text
fieldValue :: Text
fieldValue, Text
fieldInputId :: FormField -> Text
fieldInputId :: Text
fieldInputId, Maybe Violation
validatorResult :: FormField -> Maybe Violation
validatorResult :: Maybe Violation
validatorResult, Text
fieldClass :: FormField -> Text
fieldClass :: Text
fieldClass, Bool
disabled :: FormField -> Bool
disabled :: Bool
disabled, Bool
disableLabel :: FormField -> Bool
disableLabel :: Bool
disableLabel, Bool
disableValidationResult :: FormField -> Bool
disableValidationResult :: Bool
disableValidationResult, [(Text, Text)]
additionalAttributes :: FormField -> [(Text, Text)]
additionalAttributes :: [(Text, Text)]
additionalAttributes, Text
labelClass :: FormField -> Text
labelClass :: Text
labelClass, Text
placeholder :: Text
placeholder :: FormField -> Text
placeholder, Bool
required :: FormField -> Bool
required :: Bool
required, Bool
autofocus :: FormField -> Bool
autofocus :: Bool
autofocus } Html
validationResult =
            [hsx|
                {label}
                <input
                    type={inputType}
                    name={fieldName}
                    placeholder={placeholder}
                    id={fieldInputId}
                    class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    value={maybeValue}
                    required={required}
                    disabled={disabled}
                    autofocus={autofocus}
                    {...additionalAttributes}
                />

                {validationResult}
                {helpText}
          |]
            where
                label :: Html
label = Bool -> Html -> Html
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool
disableLabel Bool -> Bool -> Bool
|| Text -> Bool
null Text
fieldLabel) [hsx|<label class={labelClass} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass :: (Text, Bool)
inputClass = (CSSFramework -> FormField -> Text
styledInputClass CSSFramework
cssFramework FormField
formField, Bool
True)
                inputInvalidClass :: Text
inputInvalidClass = CSSFramework -> FormField -> Text
styledInputInvalidClass CSSFramework
cssFramework FormField
formField
                helpText :: Html
helpText = CSSFramework -> FormField -> Html
styledFormFieldHelp CSSFramework
cssFramework FormField
formField
                -- If there's no value, then we want to hide the "value" attribute.
                -- Exception: date and datetime inputs need the value attribute even when empty
                -- for HTML5 validation to work properly with the required attribute.
                maybeValue :: Maybe Text
maybeValue = if Text
fieldValue Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
"" Bool -> Bool -> Bool
&& Text
inputType Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
"date" Bool -> Bool -> Bool
&& Text
inputType Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
"datetime-local"
                    then Maybe Text
forall a. Maybe a
Nothing
                    else Text -> Maybe Text
forall a. a -> Maybe a
Just Text
fieldValue

        styledSelectFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledSelectFormField :: CSSFramework -> FormField -> Html -> Html
styledSelectFormField cssFramework :: CSSFramework
cssFramework@CSSFramework {CSSFramework -> FormField -> Text
styledInputClass :: CSSFramework -> CSSFramework -> FormField -> Text
styledInputClass :: CSSFramework -> FormField -> Text
styledInputClass, CSSFramework -> FormField -> Text
styledInputInvalidClass :: CSSFramework -> CSSFramework -> FormField -> Text
styledInputInvalidClass :: CSSFramework -> FormField -> Text
styledInputInvalidClass, CSSFramework -> FormField -> Html
styledFormFieldHelp :: CSSFramework -> CSSFramework -> FormField -> Html
styledFormFieldHelp :: CSSFramework -> FormField -> Html
styledFormFieldHelp} formField :: FormField
formField@FormField {InputType
fieldType :: FormField -> InputType
fieldType :: InputType
fieldType, Text
fieldName :: FormField -> Text
fieldName :: Text
fieldName, Text
placeholder :: FormField -> Text
placeholder :: Text
placeholder, Text
fieldLabel :: FormField -> Text
fieldLabel :: Text
fieldLabel, Text
fieldValue :: FormField -> Text
fieldValue :: Text
fieldValue, Text
fieldInputId :: FormField -> Text
fieldInputId :: Text
fieldInputId, Maybe Violation
validatorResult :: FormField -> Maybe Violation
validatorResult :: Maybe Violation
validatorResult, Text
fieldClass :: FormField -> Text
fieldClass :: Text
fieldClass, Bool
disabled :: FormField -> Bool
disabled :: Bool
disabled, Bool
disableLabel :: FormField -> Bool
disableLabel :: Bool
disableLabel, Bool
disableValidationResult :: FormField -> Bool
disableValidationResult :: Bool
disableValidationResult, [(Text, Text)]
additionalAttributes :: FormField -> [(Text, Text)]
additionalAttributes :: [(Text, Text)]
additionalAttributes, Text
labelClass :: FormField -> Text
labelClass :: Text
labelClass, Bool
required :: FormField -> Bool
required :: Bool
required, Bool
autofocus :: FormField -> Bool
autofocus :: Bool
autofocus } Html
validationResult =
            [hsx|
                {label}
                <select
                    name={fieldName}
                    id={fieldInputId}
                    class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    value={fieldValue}
                    disabled={disabled}
                    required={required}
                    autofocus={autofocus}
                    {...additionalAttributes}
                >
                    <option selected={not isValueSelected} disabled={True}>{placeholder}</option>
                    {forEach (options fieldType) (getOption)}
                </select>

                {validationResult}
                {helpText}
            |]
            where
                label :: Html
label = Bool -> Html -> Html
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
disableLabel [hsx|<label class={labelClass} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass :: (Text, Bool)
inputClass = (CSSFramework -> FormField -> Text
styledInputClass CSSFramework
cssFramework FormField
formField, Bool
True)
                inputInvalidClass :: Text
inputInvalidClass = CSSFramework -> FormField -> Text
styledInputInvalidClass CSSFramework
cssFramework FormField
formField
                helpText :: Html
helpText = CSSFramework -> FormField -> Html
styledFormFieldHelp CSSFramework
cssFramework FormField
formField

                isValueSelected :: Bool
isValueSelected = ((Text, Text) -> Bool) -> [(Text, Text)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\(Text
_, Text
optionValue) -> Text
optionValue Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
fieldValue) (InputType -> [(Text, Text)]
options InputType
fieldType)

                -- Get a single option.
                getOption :: (Text, Text) -> Html
getOption (Text
optionLabel, Text
optionValue) = [hsx|
                    <option value={optionValue} selected={optionValue == fieldValue}>
                        {optionLabel}
                    </option>
                |]

        styledTextareaFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledTextareaFormField :: CSSFramework -> FormField -> Html -> Html
styledTextareaFormField cssFramework :: CSSFramework
cssFramework@CSSFramework {CSSFramework -> FormField -> Text
styledInputClass :: CSSFramework -> CSSFramework -> FormField -> Text
styledInputClass :: CSSFramework -> FormField -> Text
styledInputClass, CSSFramework -> FormField -> Text
styledInputInvalidClass :: CSSFramework -> CSSFramework -> FormField -> Text
styledInputInvalidClass :: CSSFramework -> FormField -> Text
styledInputInvalidClass, CSSFramework -> FormField -> Html
styledFormFieldHelp :: CSSFramework -> CSSFramework -> FormField -> Html
styledFormFieldHelp :: CSSFramework -> FormField -> Html
styledFormFieldHelp} formField :: FormField
formField@FormField {InputType
fieldType :: FormField -> InputType
fieldType :: InputType
fieldType, Text
fieldName :: FormField -> Text
fieldName :: Text
fieldName, Text
fieldLabel :: FormField -> Text
fieldLabel :: Text
fieldLabel, Text
fieldValue :: FormField -> Text
fieldValue :: Text
fieldValue, Text
fieldInputId :: FormField -> Text
fieldInputId :: Text
fieldInputId, Maybe Violation
validatorResult :: FormField -> Maybe Violation
validatorResult :: Maybe Violation
validatorResult, Text
fieldClass :: FormField -> Text
fieldClass :: Text
fieldClass, Bool
disabled :: FormField -> Bool
disabled :: Bool
disabled, Bool
disableLabel :: FormField -> Bool
disableLabel :: Bool
disableLabel, Bool
disableValidationResult :: FormField -> Bool
disableValidationResult :: Bool
disableValidationResult, [(Text, Text)]
additionalAttributes :: FormField -> [(Text, Text)]
additionalAttributes :: [(Text, Text)]
additionalAttributes, Text
labelClass :: FormField -> Text
labelClass :: Text
labelClass, Text
placeholder :: FormField -> Text
placeholder :: Text
placeholder, Bool
required :: FormField -> Bool
required :: Bool
required, Bool
autofocus :: FormField -> Bool
autofocus :: Bool
autofocus } Html
validationResult =
            [hsx|
                {label}
                <textarea
                    name={fieldName}
                    placeholder={placeholder}
                    id={fieldInputId}
                    class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    required={required}
                    disabled={disabled}
                    autofocus={autofocus}
                    {...additionalAttributes}
                >{fieldValue}</textarea>{validationResult}{helpText}|]
            where
                label :: Html
label = Bool -> Html -> Html
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool
disableLabel Bool -> Bool -> Bool
|| Text -> Bool
null Text
fieldLabel) [hsx|<label class={labelClass} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass :: (Text, Bool)
inputClass = (CSSFramework -> FormField -> Text
styledInputClass CSSFramework
cssFramework FormField
formField, Bool
True)
                inputInvalidClass :: Text
inputInvalidClass = CSSFramework -> FormField -> Text
styledInputInvalidClass CSSFramework
cssFramework FormField
formField
                helpText :: Html
helpText = CSSFramework -> FormField -> Html
styledFormFieldHelp CSSFramework
cssFramework FormField
formField

        styledValidationResult :: CSSFramework -> FormField -> Blaze.Html
        styledValidationResult :: CSSFramework -> FormField -> Html
styledValidationResult CSSFramework
cssFramework formField :: FormField
formField@FormField { validatorResult :: FormField -> Maybe Violation
validatorResult = Just Violation
violation } =
            let
                Text
className :: Text = CSSFramework
cssFramework.styledValidationResultClass
                message :: Html
message = case Violation
violation of
                    TextViolation Text
text -> [hsx|{text}|]
                    HtmlViolation Text
html -> Text -> Html
forall a. ToMarkup a => a -> Html
Blaze.preEscapedToHtml Text
html
            in
                [hsx|<div class={className}>{message}</div>|]
        styledValidationResult CSSFramework
_ FormField
_ = Html
forall a. Monoid a => a
mempty

        styledSubmitButton :: r -> SubmitButton -> Html
styledSubmitButton r
cssFramework SubmitButton { Html
label :: Html
label :: SubmitButton -> Html
label, Text
buttonClass :: Text
buttonClass :: SubmitButton -> Text
buttonClass, Bool
buttonDisabled :: Bool
buttonDisabled :: SubmitButton -> Bool
buttonDisabled } =
            let Text
className :: Text = r
cssFramework.styledSubmitButtonClass
            in [hsx|<button class={classes [(className, True), (buttonClass, not (null buttonClass))]} disabled={buttonDisabled} type="submit">{label}</button>|]

        styledPagination :: CSSFramework -> PaginationView -> Blaze.Html
        styledPagination :: CSSFramework -> PaginationView -> Html
styledPagination CSSFramework
_ PaginationView
paginationView =
            [hsx|

            <div class="d-flex justify-content-md-center">
                <nav aria-label="Page Navigator" class="mr-2">
                    <ul class="pagination">
                        {paginationView.linkPrevious}
                        {paginationView.pageDotDotItems}
                        {paginationView.linkNext}
                    </ul>
                </nav>

                <div class="form-row">
                    <div class="col-auto mr-2">
                        <select class="custom-select" id="maxItemsSelect" onchange="window.location.href = this.options[this.selectedIndex].dataset.url">
                            {paginationView.itemsPerPageSelector}
                        </select>
                    </div>
                </div>

            </div>
            |]

        styledPaginationPageLink :: CSSFramework -> Pagination -> ByteString -> Int -> Blaze.Html
        styledPaginationPageLink :: CSSFramework -> Pagination -> ByteString -> Int -> Html
styledPaginationPageLink CSSFramework
_ pagination :: Pagination
pagination@Pagination {Int
currentPage :: Int
currentPage :: Pagination -> Int
currentPage} ByteString
pageUrl Int
pageNumber =
            let
                linkClass :: Text
linkClass = [(Text, Bool)] -> Text
classes [(Text, Bool)
"page-item", (Text
"active", Int
pageNumber Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
currentPage)]
            in
                [hsx|<li class={linkClass}><a class="page-link" href={pageUrl}>{show pageNumber}</a></li>|]


        styledPaginationDotDot :: CSSFramework -> Pagination -> Blaze.Html
        styledPaginationDotDot :: CSSFramework -> Pagination -> Html
styledPaginationDotDot CSSFramework
_ Pagination
_ =
            [hsx|<li class="page-item"><a class="page-link">…</a></li>|]

        styledPaginationItemsPerPageSelector :: CSSFramework -> Pagination -> (Int -> ByteString) -> Blaze.Html
        styledPaginationItemsPerPageSelector :: CSSFramework -> Pagination -> (Int -> ByteString) -> Html
styledPaginationItemsPerPageSelector CSSFramework
_ pagination :: Pagination
pagination@Pagination {Int
pageSize :: Int
pageSize :: Pagination -> Int
pageSize} Int -> ByteString
itemsPerPageUrl =
            let
                oneOption :: Int -> Blaze.Html
                oneOption :: Int -> Html
oneOption Int
n = [hsx|<option value={show n} selected={n == pageSize} data-url={itemsPerPageUrl n}>{n} items per page</option>|]
            in
                [hsx|{forEach [10,20,50,100,200] oneOption}|]

        styledPaginationLinkPrevious :: CSSFramework -> Pagination -> ByteString -> Blaze.Html
        styledPaginationLinkPrevious :: CSSFramework -> Pagination -> ByteString -> Html
styledPaginationLinkPrevious CSSFramework
_ pagination :: Pagination
pagination@Pagination {Int
currentPage :: Pagination -> Int
currentPage :: Int
currentPage} ByteString
pageUrl =
            let
                prevClass :: Text
prevClass = [(Text, Bool)] -> Text
classes [(Text, Bool)
"page-item", (Text
"disabled", Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Pagination -> Bool
hasPreviousPage Pagination
pagination)]
                url :: ByteString
url = if Pagination -> Bool
hasPreviousPage Pagination
pagination then ByteString
pageUrl else ByteString
"#"
            in
                [hsx|
                    <li class={prevClass}>
                        <a class="page-link" href={url} aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                            <span class="sr-only">Previous</span>
                        </a>
                    </li>
                |]

        styledPaginationLinkNext :: CSSFramework -> Pagination -> ByteString -> Blaze.Html
        styledPaginationLinkNext :: CSSFramework -> Pagination -> ByteString -> Html
styledPaginationLinkNext CSSFramework
_ pagination :: Pagination
pagination@Pagination {Int
currentPage :: Pagination -> Int
currentPage :: Int
currentPage} ByteString
pageUrl =
            let
                nextClass :: Text
nextClass = [(Text, Bool)] -> Text
classes [(Text, Bool)
"page-item", (Text
"disabled", Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Pagination -> Bool
hasNextPage Pagination
pagination)]
                url :: ByteString
url = if Pagination -> Bool
hasNextPage Pagination
pagination then ByteString
pageUrl else ByteString
"#"
            in
                [hsx|
                    <li class={nextClass}>
                        <a class="page-link" href={url} aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                            <span class="sr-only">Next</span>
                        </a>
                    </li>
                |]

        styledBreadcrumb :: CSSFramework -> [BreadcrumbItem]-> BreadcrumbsView -> Blaze.Html
        styledBreadcrumb :: CSSFramework -> [BreadcrumbItem] -> BreadcrumbsView -> Html
styledBreadcrumb CSSFramework
_ [BreadcrumbItem]
_ BreadcrumbsView
breadcrumbsView = [hsx|
            <nav>
                <ol class="breadcrumb">
                    {breadcrumbsView.breadcrumbItems}

                </ol>
            </nav>
        |]


        styledBreadcrumbItem :: CSSFramework -> [ BreadcrumbItem ]-> BreadcrumbItem -> Bool -> Blaze.Html
        styledBreadcrumbItem :: CSSFramework -> [BreadcrumbItem] -> BreadcrumbItem -> Bool -> Html
styledBreadcrumbItem CSSFramework
_ [BreadcrumbItem]
breadcrumbItems breadcrumbItem :: BreadcrumbItem
breadcrumbItem@BreadcrumbItem {Html
breadcrumbLabel :: Html
breadcrumbLabel :: BreadcrumbItem -> Html
breadcrumbLabel, Maybe Text
url :: Maybe Text
url :: BreadcrumbItem -> Maybe Text
url} Bool
isLast =
            let
                breadcrumbsClasses :: Text
breadcrumbsClasses = [(Text, Bool)] -> Text
classes [(Text, Bool)
"breadcrumb-item", (Text
"active", Bool
isLast)]
            in
            case Maybe Text
url of
                Maybe Text
Nothing ->  [hsx|<li class={breadcrumbsClasses}>{breadcrumbLabel}</li>|]
                Just Text
url -> [hsx|<li class={breadcrumbsClasses}><a href={url}>{breadcrumbLabel}</a></li>|]