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:
Eike Kettner
2021-01-29 20:48:27 +01:00
parent 442b76c5af
commit dd935454c9
140 changed files with 15077 additions and 214 deletions

View File

@ -4,6 +4,7 @@ module Comp.UiSettingsForm exposing
, init
, update
, view
, view2
)
import Api
@ -12,6 +13,8 @@ import Comp.BasicSizeField
import Comp.ColorTagger
import Comp.FieldListSelect
import Comp.IntField
import Comp.MenuBar as MB
import Comp.Tabs
import Data.BasicSize exposing (BasicSize)
import Data.Color exposing (Color)
import Data.Fields exposing (Field)
@ -24,6 +27,8 @@ import Html.Attributes exposing (..)
import Html.Events exposing (onCheck, onClick, onInput)
import Http
import Markdown
import Set exposing (Set)
import Styles as S
import Util.Maybe
import Util.Tag
@ -52,6 +57,8 @@ type alias Model =
, cardSubtitlePattern : PatternModel
, showPatternHelp : Bool
, searchStatsVisible : Bool
, sideMenuVisible : Bool
, openTabs : Set String
}
@ -143,6 +150,8 @@ init flags settings =
, cardSubtitlePattern = initPatternModel settings.cardSubtitleTemplate
, showPatternHelp = False
, searchStatsVisible = settings.searchStatsVisible
, sideMenuVisible = settings.sideMenuVisible
, openTabs = Set.empty
}
, Api.getTags flags "" GetTagsResp
)
@ -167,6 +176,8 @@ type Msg
| SetCardSubtitlePattern String
| TogglePatternHelpMsg
| ToggleSearchStatsVisible
| ToggleAkkordionTab String
| ToggleSideMenuVisible
@ -427,6 +438,28 @@ update sett msg model =
, Just { sett | searchStatsVisible = flag }
)
ToggleAkkordionTab title ->
let
tabs =
if Set.member title model.openTabs then
Set.remove title model.openTabs
else
Set.insert title model.openTabs
in
( { model | openTabs = tabs }
, Nothing
)
ToggleSideMenuVisible ->
let
next =
not model.sideMenuVisible
in
( { model | sideMenuVisible = next }
, Just { sett | sideMenuVisible = next }
)
--- View
@ -655,3 +688,231 @@ view flags _ model =
]
, Html.map FieldListMsg (Comp.FieldListSelect.view model.formFields)
]
--- View2
tagColorViewOpts2 : Comp.ColorTagger.ViewOpts
tagColorViewOpts2 =
{ renderItem =
\( k, v ) ->
span [ class (" label " ++ Data.Color.toString2 v) ]
[ text k ]
, label = "Choose color for tag categories"
, description = Just "Tags can be represented differently based on their category."
}
view2 : Flags -> UiSettings -> Model -> Html Msg
view2 flags settings model =
let
state tab =
if Set.member tab.title model.openTabs then
Comp.Tabs.Open
else
Comp.Tabs.Closed
in
div [ class "flex flex-col" ]
[ Comp.Tabs.akkordion
Comp.Tabs.defaultStyle
(\t -> ( state t, ToggleAkkordionTab t.title ))
(settingFormTabs flags settings model)
]
settingFormTabs : Flags -> UiSettings -> Model -> List (Comp.Tabs.Tab Msg)
settingFormTabs flags _ model =
[ { title = "General"
, info = Nothing
, body =
[ div [ class "mb-4 " ]
[ MB.viewItem <|
MB.Checkbox
{ id = "uisetting-sidemenu-visible"
, label = "Show side menu by default"
, tagger = \_ -> ToggleSideMenuVisible
, value = model.sideMenuVisible
}
]
]
}
, { title = "Item Search"
, info = Nothing
, body =
[ Html.map SearchPageSizeMsg
(Comp.IntField.viewWithInfo2
("Maximum results in one page when searching items. At most "
++ String.fromInt flags.config.maxPageSize
++ "."
)
model.itemSearchPageSize
"mb-4"
model.searchPageSizeModel
)
, div [ class "mb-4" ]
[ MB.viewItem <|
MB.Checkbox
{ id = "uisetting-searchstats-visible"
, value = model.searchStatsVisible
, tagger = \_ -> ToggleSearchStatsVisible
, label = "Show basic search statistics by default"
}
]
]
}
, { title = "Item Cards"
, info = Nothing
, body =
[ Html.map NoteLengthMsg
(Comp.IntField.viewWithInfo2
("Maximum size of the item notes to display in card view. Between 0 - "
++ String.fromInt flags.config.maxNoteLength
++ "."
)
model.itemSearchNoteLength
"mb-4"
model.searchNoteLengthModel
)
, Html.map CardPreviewSizeMsg
(Comp.BasicSizeField.view2
"mb-4"
"Size of item preview"
model.cardPreviewSize
)
, div [ class "mb-4" ]
[ label [ class S.inputLabel ]
[ text "Card Title Pattern"
, a
[ class "float-right"
, class S.link
, title "Toggle pattern help text"
, href "#"
, onClick TogglePatternHelpMsg
]
[ i [ class "fa fa-question" ] []
]
]
, input
[ type_ "text"
, Maybe.withDefault "" model.cardTitlePattern.pattern |> value
, onInput SetCardTitlePattern
, class S.textInput
]
[]
]
, div [ class "mb-4" ]
[ label [ class S.inputLabel ]
[ text "Card Subtitle Pattern"
, a
[ class "float-right"
, class S.link
, title "Toggle pattern help text"
, href "#"
, onClick TogglePatternHelpMsg
]
[ i [ class "fa fa-question" ] []
]
]
, input
[ type_ "text"
, Maybe.withDefault "" model.cardSubtitlePattern.pattern |> value
, onInput SetCardSubtitlePattern
, class S.textInput
]
[]
]
, Markdown.toHtml
[ classList
[ ( S.message, True )
, ( "hidden", not model.showPatternHelp )
]
]
IT.helpMessage
]
}
, { title = "Search Menu"
, info = Nothing
, body =
[ Html.map SearchMenuTagMsg
(Comp.IntField.viewWithInfo2
"How many tags to display in search menu at once. Others can be expanded. Use 0 to always show all."
model.searchMenuTagCount
"mb-4"
model.searchMenuTagCountModel
)
, Html.map SearchMenuTagCatMsg
(Comp.IntField.viewWithInfo2
"How many categories to display in search menu at once. Others can be expanded. Use 0 to always show all."
model.searchMenuTagCatCount
"mb-4"
model.searchMenuTagCatCountModel
)
, Html.map SearchMenuFolderMsg
(Comp.IntField.viewWithInfo2
"How many folders to display in search menu at once. Other folders can be expanded. Use 0 to always show all."
model.searchMenuFolderCount
"mb-4"
model.searchMenuFolderCountModel
)
]
}
, { title = "Item Detail"
, info = Nothing
, body =
[ div [ class "mb-4" ]
[ MB.viewItem <|
MB.Checkbox
{ tagger = \_ -> TogglePdfPreview
, label = "Browser-native PDF preview"
, value = model.nativePdfPreview
, id = "uisetting-pdfpreview-toggle"
}
]
, div [ class "mb-4" ]
[ MB.viewItem <|
MB.Checkbox
{ tagger = \_ -> ToggleItemDetailShortcuts
, label = "Use keyboard shortcuts for navigation and confirm/unconfirm with open edit menu."
, value = model.itemDetailShortcuts
, id = "uisetting-itemdetailshortcuts-toggle"
}
]
, div [ class "mb-4 hidden" ]
[ MB.viewItem <|
MB.Checkbox
{ id = "uisetting-editmenu-visible"
, value = model.editMenuVisible
, tagger = \_ -> ToggleEditMenuVisible
, label = "Show edit side menu by default"
}
]
]
}
, { title = "Tag Category Colors"
, info = Nothing
, body =
[ Html.map TagColorMsg
(Comp.ColorTagger.view2
model.tagColors
tagColorViewOpts2
model.tagColorModel
)
]
}
, { title = "Fields"
, info = Nothing
, body =
[ span [ class "opacity-50 text-sm" ]
[ text "Choose which fields to display in search and edit menus."
]
, Html.map FieldListMsg
(Comp.FieldListSelect.view2
"px-2"
model.formFields
)
]
}
]