Eike Kettner dd935454c9 First version of new ui based on tailwind
This drops fomantic-ui as css toolkit and introduces tailwindcss. With
tailwind there are no predefined components, but it's very easy to
create those. So customizing the look&feel is much simpler, most of
the time no additional css is needed.

This requires a complete rewrite of the markup + styles. Luckily all
logic can be kept as is. The now old ui is not removed, it is still
available by using a request header `Docspell-Ui` with a value of `1`
for the old ui and `2` for the new ui.

Another addition is "dev mode", where docspell serves assets with a
no-cache header, to disable browser caching. This makes developing a
lot easier.
2021-02-14 01:46:13 +01:00

181 lines
4.3 KiB
Elm

module Comp.IntField exposing
( Model
, Msg
, init
, update
, view
, viewWithInfo
, viewWithInfo2
)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput)
import Markdown
import Styles as S
type alias Model =
{ min : Maybe Int
, max : Maybe Int
, label : String
, error : Maybe String
, lastInput : String
, optional : Bool
}
type Msg
= SetValue String
init : Maybe Int -> Maybe Int -> Bool -> String -> Model
init min max opt label =
{ min = min
, max = max
, label = label
, error = Nothing
, lastInput = ""
, optional = opt
}
tooLow : Model -> Int -> Bool
tooLow model n =
Maybe.map ((<) n) model.min
|> Maybe.withDefault (not model.optional)
tooHigh : Model -> Int -> Bool
tooHigh model n =
Maybe.map ((>) n) model.max
|> Maybe.withDefault (not model.optional)
update : Msg -> Model -> ( Model, Maybe Int )
update msg model =
let
tooHighError =
Maybe.withDefault 0 model.max
|> String.fromInt
|> (++) "Number must be <= "
tooLowError =
Maybe.withDefault 0 model.min
|> String.fromInt
|> (++) "Number must be >= "
in
case msg of
SetValue str ->
let
m =
{ model | lastInput = str }
in
case String.toInt str of
Just n ->
if tooLow model n then
( { m | error = Just tooLowError }
, Nothing
)
else if tooHigh model n then
( { m | error = Just tooHighError }
, Nothing
)
else
( { m | error = Nothing }, Just n )
Nothing ->
if model.optional && String.trim str == "" then
( { m | error = Nothing }, Nothing )
else
( { m | error = Just ("'" ++ str ++ "' is not a valid number!") }
, Nothing
)
view : Maybe Int -> String -> Model -> Html Msg
view =
viewWithInfo ""
viewWithInfo : String -> Maybe Int -> String -> Model -> Html Msg
viewWithInfo info nval classes model =
div
[ classList
[ ( classes, True )
, ( "error", model.error /= Nothing )
]
]
[ label [] [ text model.label ]
, input
[ type_ "text"
, Maybe.map String.fromInt nval
|> Maybe.withDefault model.lastInput
|> value
, onInput SetValue
]
[]
, span
[ classList
[ ( "small-info", True )
, ( "hidden invisible", info == "" )
]
]
[ Markdown.toHtml [] info
]
, div
[ classList
[ ( "ui pointing red basic label", True )
, ( "hidden", model.error == Nothing )
]
]
[ Maybe.withDefault "" model.error |> text
]
]
--- View2
viewWithInfo2 : String -> Maybe Int -> String -> Model -> Html Msg
viewWithInfo2 info nval classes model =
div
[ classList
[ ( classes, True )
, ( "error", model.error /= Nothing )
]
]
[ label [ class S.inputLabel ]
[ text model.label
]
, input
[ type_ "text"
, Maybe.map String.fromInt nval
|> Maybe.withDefault model.lastInput
|> value
, onInput SetValue
, class S.textInput
]
[]
, span
[ classList
[ ( "hidden", info == "" )
]
, class "opacity-50 text-sm"
]
[ Markdown.toHtml [] info
]
, div
[ classList
[ ( "hidden", model.error == Nothing )
]
, class S.errorMessage
]
[ Maybe.withDefault "" model.error |> text
]
]