mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-09-30 08:38:22 +00:00
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.
This commit is contained in:
@@ -38,22 +38,6 @@ type alias Model =
|
||||
}
|
||||
|
||||
|
||||
dropzoneSettings : Comp.Dropzone.Settings
|
||||
dropzoneSettings =
|
||||
let
|
||||
ds =
|
||||
Comp.Dropzone.defaultSettings
|
||||
in
|
||||
{ ds
|
||||
| classList =
|
||||
\m ->
|
||||
[ ( "ui attached blue placeholder segment dropzone", True )
|
||||
, ( "dragging", m.hover )
|
||||
, ( "disabled", not m.active )
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
mkLanguageItem : Language -> Comp.FixedDropdown.Item Language
|
||||
mkLanguageItem lang =
|
||||
Comp.FixedDropdown.Item lang (Data.Language.toName lang)
|
||||
@@ -67,7 +51,7 @@ emptyModel =
|
||||
, completed = Set.empty
|
||||
, errored = Set.empty
|
||||
, loading = Dict.empty
|
||||
, dropzone = Comp.Dropzone.init dropzoneSettings
|
||||
, dropzone = Comp.Dropzone.init []
|
||||
, skipDuplicates = True
|
||||
, languageModel =
|
||||
Comp.FixedDropdown.init
|
||||
|
@@ -23,7 +23,7 @@ view mid model =
|
||||
[ div [ class "ui top attached segment" ]
|
||||
[ renderForm model
|
||||
]
|
||||
, Html.map DropzoneMsg (Comp.Dropzone.view model.dropzone)
|
||||
, Html.map DropzoneMsg (Comp.Dropzone.view dropzoneSettings model.dropzone)
|
||||
, div [ class "ui bottom attached segment" ]
|
||||
[ a [ class "ui primary button", href "#", onClick SubmitUpload ]
|
||||
[ text "Submit"
|
||||
@@ -50,6 +50,22 @@ view mid model =
|
||||
]
|
||||
|
||||
|
||||
dropzoneSettings : Comp.Dropzone.Settings
|
||||
dropzoneSettings =
|
||||
let
|
||||
ds =
|
||||
Comp.Dropzone.defaultSettings
|
||||
in
|
||||
{ ds
|
||||
| classList =
|
||||
\m ->
|
||||
[ ( "ui attached blue placeholder segment dropzone", True )
|
||||
, ( "dragging", m.hover )
|
||||
, ( "disabled", not m.active )
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
renderErrorMsg : Model -> Html Msg
|
||||
renderErrorMsg _ =
|
||||
div [ class "row" ]
|
||||
|
280
modules/webapp/src/main/elm/Page/Upload/View2.elm
Normal file
280
modules/webapp/src/main/elm/Page/Upload/View2.elm
Normal file
@@ -0,0 +1,280 @@
|
||||
module Page.Upload.View2 exposing (viewContent, viewSidebar)
|
||||
|
||||
import Comp.Dropzone
|
||||
import Comp.FixedDropdown
|
||||
import Comp.Progress
|
||||
import Data.DropdownStyle as DS
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Dict
|
||||
import File exposing (File)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onCheck, onClick)
|
||||
import Page exposing (Page(..))
|
||||
import Page.Upload.Data exposing (..)
|
||||
import Styles as S
|
||||
import Util.File exposing (makeFileId)
|
||||
import Util.Maybe
|
||||
import Util.Size
|
||||
|
||||
|
||||
viewSidebar : Maybe String -> Bool -> Flags -> UiSettings -> Model -> Html Msg
|
||||
viewSidebar _ _ _ _ _ =
|
||||
div
|
||||
[ id "sidebar"
|
||||
, class "hidden"
|
||||
]
|
||||
[]
|
||||
|
||||
|
||||
viewContent : Maybe String -> Flags -> UiSettings -> Model -> Html Msg
|
||||
viewContent mid _ _ model =
|
||||
div
|
||||
[ id "content"
|
||||
, class S.content
|
||||
]
|
||||
[ div [ class "px-0 flex flex-col" ]
|
||||
[ div [ class "py-4" ]
|
||||
[ renderForm model
|
||||
]
|
||||
, div [ class "py-0" ]
|
||||
[ Html.map DropzoneMsg
|
||||
(Comp.Dropzone.view2 model.dropzone)
|
||||
]
|
||||
, div [ class "py-4" ]
|
||||
[ a
|
||||
[ class S.primaryButton
|
||||
, href "#"
|
||||
, onClick SubmitUpload
|
||||
]
|
||||
[ text "Submit"
|
||||
]
|
||||
, a
|
||||
[ class S.secondaryButton
|
||||
, class "ml-2"
|
||||
, href "#"
|
||||
, onClick Clear
|
||||
]
|
||||
[ text "Reset"
|
||||
]
|
||||
]
|
||||
]
|
||||
, renderErrorMsg model
|
||||
, renderSuccessMsg (Util.Maybe.nonEmpty mid) model
|
||||
, renderUploads model
|
||||
]
|
||||
|
||||
|
||||
renderForm : Model -> Html Msg
|
||||
renderForm model =
|
||||
div [ class "row" ]
|
||||
[ Html.form [ action "#" ]
|
||||
[ div [ class "flex flex-col mb-3" ]
|
||||
[ label [ class "inline-flex items-center" ]
|
||||
[ input
|
||||
[ type_ "radio"
|
||||
, checked model.incoming
|
||||
, onCheck (\_ -> ToggleIncoming)
|
||||
, class S.radioInput
|
||||
]
|
||||
[]
|
||||
, span [ class "ml-2" ] [ text "Incoming" ]
|
||||
]
|
||||
, label [ class "inline-flex items-center" ]
|
||||
[ input
|
||||
[ type_ "radio"
|
||||
, checked (not model.incoming)
|
||||
, onCheck (\_ -> ToggleIncoming)
|
||||
, class S.radioInput
|
||||
]
|
||||
[]
|
||||
, span [ class "ml-2" ] [ text "Outgoing" ]
|
||||
]
|
||||
]
|
||||
, div [ class "flex flex-col mb-3" ]
|
||||
[ label [ class "inline-flex items-center" ]
|
||||
[ input
|
||||
[ type_ "checkbox"
|
||||
, checked model.singleItem
|
||||
, onCheck (\_ -> ToggleSingleItem)
|
||||
, class S.checkboxInput
|
||||
]
|
||||
[]
|
||||
, span [ class "ml-2" ]
|
||||
[ text "All files are one single item"
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "flex flex-col mb-3" ]
|
||||
[ label [ class "inline-flex items-center" ]
|
||||
[ input
|
||||
[ type_ "checkbox"
|
||||
, checked model.skipDuplicates
|
||||
, onCheck (\_ -> ToggleSkipDuplicates)
|
||||
, class S.checkboxInput
|
||||
]
|
||||
[]
|
||||
, span [ class "ml-2" ]
|
||||
[ text "Skip files already present in docspell"
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "flex flex-col mb-3" ]
|
||||
[ label [ class "inline-flex items-center mb-2" ]
|
||||
[ span [ class "mr-2" ] [ text "Language:" ]
|
||||
, Html.map LanguageMsg
|
||||
(Comp.FixedDropdown.viewStyled2
|
||||
(DS.mainStyleWith "w-40")
|
||||
False
|
||||
(Maybe.map mkLanguageItem model.language)
|
||||
model.languageModel
|
||||
)
|
||||
]
|
||||
, div [ class "text-gray-400 text-xs" ]
|
||||
[ text "Used for text extraction and analysis. The collective's "
|
||||
, text "default language is used if not specified here."
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
renderErrorMsg : Model -> Html Msg
|
||||
renderErrorMsg model =
|
||||
div
|
||||
[ class "row"
|
||||
, classList [ ( "hidden", not (isDone model && hasErrors model) ) ]
|
||||
]
|
||||
[ div [ class "mt-4" ]
|
||||
[ div [ class S.errorMessage ]
|
||||
[ text "There were errors uploading some files."
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
renderSuccessMsg : Bool -> Model -> Html Msg
|
||||
renderSuccessMsg public model =
|
||||
div
|
||||
[ class "row"
|
||||
, classList [ ( "hidden", List.isEmpty model.files || not (isSuccessAll model) ) ]
|
||||
]
|
||||
[ div [ class "mt-4" ]
|
||||
[ div [ class S.successMessage ]
|
||||
[ h3 [ class S.header2, class "text-green-800 dark:text-lime-800" ]
|
||||
[ i [ class "fa fa-smile font-thin" ] []
|
||||
, span [ class "ml-2" ]
|
||||
[ text "All files uploaded"
|
||||
]
|
||||
]
|
||||
, p
|
||||
[ classList [ ( "hidden", public ) ]
|
||||
]
|
||||
[ text "Your files have been successfully uploaded. "
|
||||
, text "They are now being processed. Check the "
|
||||
, a
|
||||
[ class S.successMessageLink
|
||||
, Page.href HomePage
|
||||
]
|
||||
[ text "Items page"
|
||||
]
|
||||
, text " later where the files will arrive eventually. Or go to the "
|
||||
, a
|
||||
[ class S.successMessageLink
|
||||
, Page.href QueuePage
|
||||
]
|
||||
[ text "Processing Page"
|
||||
]
|
||||
, text " to view the current processing state."
|
||||
]
|
||||
, p []
|
||||
[ text "Click "
|
||||
, a
|
||||
[ class S.successMessageLink
|
||||
, href "#"
|
||||
, onClick Clear
|
||||
]
|
||||
[ text "Reset"
|
||||
]
|
||||
, text " to upload more files."
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
renderUploads : Model -> Html Msg
|
||||
renderUploads model =
|
||||
div
|
||||
[ class "mt-4"
|
||||
, classList [ ( "hidden", List.isEmpty model.files || isSuccessAll model ) ]
|
||||
]
|
||||
[ div [ class "sixteen wide column" ]
|
||||
[ div [ class "ui basic segment" ]
|
||||
[ h2 [ class S.header2 ]
|
||||
[ text "Selected Files"
|
||||
]
|
||||
, div [ class "ui items" ] <|
|
||||
if model.singleItem then
|
||||
List.map (renderFileItem model (Just uploadAllTracker)) model.files
|
||||
|
||||
else
|
||||
List.map (renderFileItem model Nothing) model.files
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
getProgress : Model -> File -> Int
|
||||
getProgress model file =
|
||||
let
|
||||
key =
|
||||
if model.singleItem then
|
||||
uploadAllTracker
|
||||
|
||||
else
|
||||
makeFileId file
|
||||
in
|
||||
Dict.get key model.loading
|
||||
|> Maybe.withDefault 0
|
||||
|
||||
|
||||
renderFileItem : Model -> Maybe String -> File -> Html Msg
|
||||
renderFileItem model _ file =
|
||||
let
|
||||
name =
|
||||
File.name file
|
||||
|
||||
size =
|
||||
File.size file
|
||||
|> toFloat
|
||||
|> Util.Size.bytesReadable Util.Size.B
|
||||
in
|
||||
div [ class "flex flex-col w-full mb-4" ]
|
||||
[ div [ class "flex flex-row items-center" ]
|
||||
[ div [ class "inline-flex items-center" ]
|
||||
[ i
|
||||
[ classList
|
||||
[ ( "mr-2 text-lg", True )
|
||||
, ( "fa fa-file font-thin", isIdle model file )
|
||||
, ( "fa fa-spinner animate-spin ", isLoading model file )
|
||||
, ( "fa fa-check ", isCompleted model file )
|
||||
, ( "fa fa-bolt", isError model file )
|
||||
]
|
||||
]
|
||||
[]
|
||||
, div [ class "middle aligned content" ]
|
||||
[ div [ class "header" ]
|
||||
[ text name
|
||||
]
|
||||
]
|
||||
]
|
||||
, div [ class "flex-grow inline-flex justify-end" ]
|
||||
[ text size
|
||||
]
|
||||
]
|
||||
, div [ class "h-4" ]
|
||||
[ Comp.Progress.progress2 (getProgress model file)
|
||||
]
|
||||
]
|
Reference in New Issue
Block a user