mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 10:28:27 +00:00
Editable dashboard
This commit is contained in:
467
modules/webapp/src/main/elm/Comp/BoxEdit.elm
Normal file
467
modules/webapp/src/main/elm/Comp/BoxEdit.elm
Normal file
@ -0,0 +1,467 @@
|
||||
module Comp.BoxEdit exposing
|
||||
( BoxAction(..)
|
||||
, Model
|
||||
, Msg
|
||||
, UpdateResult
|
||||
, init
|
||||
, update
|
||||
, view
|
||||
)
|
||||
|
||||
import Comp.Basic as B
|
||||
import Comp.BoxMessageEdit
|
||||
import Comp.BoxQueryEdit
|
||||
import Comp.BoxStatsEdit
|
||||
import Comp.BoxUploadEdit
|
||||
import Comp.FixedDropdown
|
||||
import Comp.MenuBar as MB
|
||||
import Data.Box exposing (Box)
|
||||
import Data.BoxContent exposing (BoxContent(..))
|
||||
import Data.DropdownStyle as DS
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (Html, div, i, input, label, text)
|
||||
import Html.Attributes exposing (class, classList, placeholder, type_, value)
|
||||
import Html.Events exposing (onInput, onMouseEnter, onMouseLeave)
|
||||
import Messages.Comp.BoxEdit exposing (Texts)
|
||||
import Styles as S
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ box : Box
|
||||
, content : ContentModel
|
||||
, colspanModel : Comp.FixedDropdown.Model Int
|
||||
, focus : Bool
|
||||
, deleteRequested : Bool
|
||||
}
|
||||
|
||||
|
||||
type ContentModel
|
||||
= ContentMessage Comp.BoxMessageEdit.Model
|
||||
| ContentQuery Comp.BoxQueryEdit.Model
|
||||
| ContentStats Comp.BoxStatsEdit.Model
|
||||
| ContentUpload Comp.BoxUploadEdit.Model
|
||||
|
||||
|
||||
type Msg
|
||||
= ToggleVisible
|
||||
| ToggleDecoration
|
||||
| SetName String
|
||||
| ColspanMsg (Comp.FixedDropdown.Msg Int)
|
||||
| MessageMsg Comp.BoxMessageEdit.Msg
|
||||
| UploadMsg Comp.BoxUploadEdit.Msg
|
||||
| QueryMsg Comp.BoxQueryEdit.Msg
|
||||
| StatsMsg Comp.BoxStatsEdit.Msg
|
||||
| SetFocus Bool
|
||||
| RequestDelete
|
||||
| DeleteBox
|
||||
| CancelDelete
|
||||
| MoveLeft
|
||||
| MoveRight
|
||||
|
||||
|
||||
init : Flags -> Box -> ( Model, Cmd Msg, Sub Msg )
|
||||
init flags box =
|
||||
let
|
||||
( cm, cc, cs ) =
|
||||
contentInit flags box.content
|
||||
in
|
||||
( { box = box
|
||||
, content = cm
|
||||
, colspanModel = Comp.FixedDropdown.init [ 1, 2, 3, 4, 5 ]
|
||||
, focus = False
|
||||
, deleteRequested = False
|
||||
}
|
||||
, cc
|
||||
, cs
|
||||
)
|
||||
|
||||
|
||||
contentInit : Flags -> BoxContent -> ( ContentModel, Cmd Msg, Sub Msg )
|
||||
contentInit flags content =
|
||||
case content of
|
||||
BoxMessage data ->
|
||||
( ContentMessage (Comp.BoxMessageEdit.init data), Cmd.none, Sub.none )
|
||||
|
||||
BoxUpload data ->
|
||||
let
|
||||
( um, uc ) =
|
||||
Comp.BoxUploadEdit.init flags data
|
||||
in
|
||||
( ContentUpload um, Cmd.map UploadMsg uc, Sub.none )
|
||||
|
||||
BoxQuery data ->
|
||||
let
|
||||
( qm, qc, qs ) =
|
||||
Comp.BoxQueryEdit.init flags data
|
||||
in
|
||||
( ContentQuery qm, Cmd.map QueryMsg qc, Sub.map QueryMsg qs )
|
||||
|
||||
BoxStats data ->
|
||||
let
|
||||
( qm, qc, qs ) =
|
||||
Comp.BoxStatsEdit.init flags data
|
||||
in
|
||||
( ContentStats qm, Cmd.map StatsMsg qc, Sub.map StatsMsg qs )
|
||||
|
||||
|
||||
|
||||
--- Update
|
||||
|
||||
|
||||
type BoxAction
|
||||
= BoxNoAction
|
||||
| BoxMoveLeft
|
||||
| BoxMoveRight
|
||||
| BoxDelete
|
||||
|
||||
|
||||
type alias UpdateResult =
|
||||
{ model : Model
|
||||
, cmd : Cmd Msg
|
||||
, sub : Sub Msg
|
||||
, action : BoxAction
|
||||
}
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> UpdateResult
|
||||
update flags msg model =
|
||||
case msg of
|
||||
MessageMsg lm ->
|
||||
case model.content of
|
||||
ContentMessage m ->
|
||||
let
|
||||
( mm, data ) =
|
||||
Comp.BoxMessageEdit.update lm m
|
||||
|
||||
boxn =
|
||||
model.box
|
||||
|
||||
box_ =
|
||||
{ boxn | content = BoxMessage data }
|
||||
in
|
||||
{ model = { model | content = ContentMessage mm, box = box_ }
|
||||
, cmd = Cmd.none
|
||||
, sub = Sub.none
|
||||
, action = BoxNoAction
|
||||
}
|
||||
|
||||
_ ->
|
||||
unit model
|
||||
|
||||
UploadMsg lm ->
|
||||
case model.content of
|
||||
ContentUpload m ->
|
||||
let
|
||||
( um, data ) =
|
||||
Comp.BoxUploadEdit.update lm m
|
||||
|
||||
boxn =
|
||||
model.box
|
||||
|
||||
box_ =
|
||||
{ boxn | content = BoxUpload data }
|
||||
in
|
||||
{ model = { model | content = ContentUpload um, box = box_ }
|
||||
, cmd = Cmd.none
|
||||
, sub = Sub.none
|
||||
, action = BoxNoAction
|
||||
}
|
||||
|
||||
_ ->
|
||||
unit model
|
||||
|
||||
QueryMsg lm ->
|
||||
case model.content of
|
||||
ContentQuery m ->
|
||||
let
|
||||
result =
|
||||
Comp.BoxQueryEdit.update flags lm m
|
||||
|
||||
boxn =
|
||||
model.box
|
||||
|
||||
box_ =
|
||||
{ boxn | content = BoxQuery result.data }
|
||||
in
|
||||
{ model = { model | content = ContentQuery result.model, box = box_ }
|
||||
, cmd = Cmd.map QueryMsg result.cmd
|
||||
, sub = Sub.map QueryMsg result.sub
|
||||
, action = BoxNoAction
|
||||
}
|
||||
|
||||
_ ->
|
||||
unit model
|
||||
|
||||
StatsMsg lm ->
|
||||
case model.content of
|
||||
ContentStats m ->
|
||||
let
|
||||
result =
|
||||
Comp.BoxStatsEdit.update flags lm m
|
||||
|
||||
boxn =
|
||||
model.box
|
||||
|
||||
box_ =
|
||||
{ boxn | content = BoxStats result.data }
|
||||
in
|
||||
{ model = { model | content = ContentStats result.model, box = box_ }
|
||||
, cmd = Cmd.map StatsMsg result.cmd
|
||||
, sub = Sub.map StatsMsg result.sub
|
||||
, action = BoxNoAction
|
||||
}
|
||||
|
||||
_ ->
|
||||
unit model
|
||||
|
||||
ColspanMsg lm ->
|
||||
let
|
||||
( cm, num ) =
|
||||
Comp.FixedDropdown.update lm model.colspanModel
|
||||
|
||||
boxn =
|
||||
model.box
|
||||
|
||||
box_ =
|
||||
{ boxn | colspan = Maybe.withDefault boxn.colspan num }
|
||||
in
|
||||
unit { model | box = box_, colspanModel = cm }
|
||||
|
||||
ToggleVisible ->
|
||||
let
|
||||
box =
|
||||
model.box
|
||||
|
||||
box_ =
|
||||
{ box | visible = not box.visible }
|
||||
in
|
||||
unit { model | box = box_ }
|
||||
|
||||
ToggleDecoration ->
|
||||
let
|
||||
box =
|
||||
model.box
|
||||
|
||||
box_ =
|
||||
{ box | decoration = not box.decoration }
|
||||
in
|
||||
unit { model | box = box_ }
|
||||
|
||||
SetName name ->
|
||||
let
|
||||
box =
|
||||
model.box
|
||||
|
||||
box_ =
|
||||
{ box | name = name }
|
||||
in
|
||||
unit { model | box = box_ }
|
||||
|
||||
SetFocus flag ->
|
||||
unit { model | focus = flag }
|
||||
|
||||
RequestDelete ->
|
||||
unit { model | deleteRequested = True }
|
||||
|
||||
DeleteBox ->
|
||||
UpdateResult model Cmd.none Sub.none BoxDelete
|
||||
|
||||
CancelDelete ->
|
||||
unit { model | deleteRequested = False }
|
||||
|
||||
MoveLeft ->
|
||||
UpdateResult model Cmd.none Sub.none BoxMoveLeft
|
||||
|
||||
MoveRight ->
|
||||
UpdateResult model Cmd.none Sub.none BoxMoveRight
|
||||
|
||||
|
||||
unit : Model -> UpdateResult
|
||||
unit model =
|
||||
UpdateResult model Cmd.none Sub.none BoxNoAction
|
||||
|
||||
|
||||
|
||||
--- View
|
||||
|
||||
|
||||
view : Texts -> Flags -> UiSettings -> Model -> Html Msg
|
||||
view texts flags settings model =
|
||||
div
|
||||
[ class (S.box ++ "rounded md:relative")
|
||||
, class " h-full"
|
||||
, classList [ ( "ring ring-opacity-50 ring-blue-600 dark:ring-sky-600", model.focus ) ]
|
||||
, onMouseEnter (SetFocus True)
|
||||
, onMouseLeave (SetFocus False)
|
||||
]
|
||||
[ B.contentDimmer model.deleteRequested
|
||||
(div [ class "flex flex-col" ]
|
||||
[ div [ class "text-xl" ]
|
||||
[ i [ class "fa fa-info-circle mr-2" ] []
|
||||
, text texts.reallyDeleteBox
|
||||
]
|
||||
, div [ class "mt-4 flex flex-row items-center space-x-2" ]
|
||||
[ MB.viewItem <|
|
||||
MB.DeleteButton
|
||||
{ tagger = DeleteBox
|
||||
, title = ""
|
||||
, label = texts.basics.yes
|
||||
, icon = Just "fa fa-check"
|
||||
}
|
||||
, MB.viewItem <|
|
||||
MB.SecondaryButton
|
||||
{ tagger = CancelDelete
|
||||
, title = ""
|
||||
, label = texts.basics.no
|
||||
, icon = Just "fa fa-times"
|
||||
}
|
||||
]
|
||||
]
|
||||
)
|
||||
, boxHeader texts model
|
||||
, formHeader (texts.boxContent.forContent model.box.content)
|
||||
, div [ class "mb-4 pl-2" ]
|
||||
[ metaForm texts flags model
|
||||
]
|
||||
, formHeader texts.contentProperties
|
||||
, div [ class "pl-4 pr-2 py-2 h-5/6" ]
|
||||
[ boxContent texts flags settings model
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
formHeader : String -> Html msg
|
||||
formHeader heading =
|
||||
div
|
||||
[ class "mx-2 border-b dark:border-slate-500 text-lg mt-1"
|
||||
]
|
||||
[ text heading
|
||||
]
|
||||
|
||||
|
||||
metaForm : Texts -> Flags -> Model -> Html Msg
|
||||
metaForm texts _ model =
|
||||
let
|
||||
colspanCfg =
|
||||
{ display = String.fromInt
|
||||
, icon = \_ -> Nothing
|
||||
, selectPlaceholder = ""
|
||||
, style = DS.mainStyle
|
||||
}
|
||||
in
|
||||
div [ class "my-1 px-2 " ]
|
||||
[ div []
|
||||
[ label [ class S.inputLabel ]
|
||||
[ text texts.basics.name
|
||||
]
|
||||
, input
|
||||
[ type_ "text"
|
||||
, placeholder texts.namePlaceholder
|
||||
, class S.textInput
|
||||
, value model.box.name
|
||||
, onInput SetName
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div [ class "mt-1" ]
|
||||
[ MB.viewItem <|
|
||||
MB.Checkbox
|
||||
{ tagger = \_ -> ToggleVisible
|
||||
, label = texts.visible
|
||||
, value = model.box.visible
|
||||
, id = ""
|
||||
}
|
||||
]
|
||||
, div [ class "mt-1" ]
|
||||
[ MB.viewItem <|
|
||||
MB.Checkbox
|
||||
{ tagger = \_ -> ToggleDecoration
|
||||
, label = texts.decorations
|
||||
, value = model.box.decoration
|
||||
, id = ""
|
||||
}
|
||||
]
|
||||
, div [ class "mt-1" ]
|
||||
[ label [ class S.inputLabel ]
|
||||
[ text texts.colspan ]
|
||||
, Html.map ColspanMsg
|
||||
(Comp.FixedDropdown.viewStyled2
|
||||
colspanCfg
|
||||
False
|
||||
(Just model.box.colspan)
|
||||
model.colspanModel
|
||||
)
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
boxHeader : Texts -> Model -> Html Msg
|
||||
boxHeader texts model =
|
||||
div
|
||||
[ class "flex flex-row py-1 bg-blue-50 dark:bg-slate-700 rounded-t"
|
||||
]
|
||||
[ div [ class "flex flex-row items-center text-lg tracking-medium italic px-2" ]
|
||||
[ i
|
||||
[ class (Data.Box.boxIcon model.box)
|
||||
, class "mr-2"
|
||||
]
|
||||
[]
|
||||
, text model.box.name
|
||||
]
|
||||
, div [ class "flex flex-grow justify-end pr-1" ]
|
||||
[ MB.viewItem <|
|
||||
MB.CustomButton
|
||||
{ tagger = MoveLeft
|
||||
, title = texts.moveToLeft
|
||||
, label = ""
|
||||
, icon = Just "fa fa-arrow-left"
|
||||
, inputClass =
|
||||
[ ( S.secondaryBasicButton, True )
|
||||
, ( "text-xs", True )
|
||||
]
|
||||
}
|
||||
, MB.viewItem <|
|
||||
MB.CustomButton
|
||||
{ tagger = MoveRight
|
||||
, title = texts.moveToRight
|
||||
, label = ""
|
||||
, icon = Just "fa fa-arrow-right"
|
||||
, inputClass =
|
||||
[ ( S.secondaryBasicButton, True )
|
||||
, ( "text-xs mr-3", True )
|
||||
]
|
||||
}
|
||||
, MB.viewItem <|
|
||||
MB.CustomButton
|
||||
{ tagger = RequestDelete
|
||||
, title = texts.deleteBox
|
||||
, label = ""
|
||||
, icon = Just "fa fa-trash"
|
||||
, inputClass =
|
||||
[ ( S.deleteButton, True )
|
||||
, ( "text-xs", True )
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
boxContent : Texts -> Flags -> UiSettings -> Model -> Html Msg
|
||||
boxContent texts flags settings model =
|
||||
case model.content of
|
||||
ContentMessage m ->
|
||||
Html.map MessageMsg
|
||||
(Comp.BoxMessageEdit.view texts.messageEdit m)
|
||||
|
||||
ContentUpload m ->
|
||||
Html.map UploadMsg
|
||||
(Comp.BoxUploadEdit.view texts.uploadEdit m)
|
||||
|
||||
ContentQuery m ->
|
||||
Html.map QueryMsg
|
||||
(Comp.BoxQueryEdit.view texts.queryEdit settings m)
|
||||
|
||||
ContentStats m ->
|
||||
Html.map StatsMsg
|
||||
(Comp.BoxStatsEdit.view texts.statsEdit settings m)
|
Reference in New Issue
Block a user