mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 10:28:27 +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:
343
modules/webapp/src/main/elm/Comp/ItemDetail/SingleAttachment.elm
Normal file
343
modules/webapp/src/main/elm/Comp/ItemDetail/SingleAttachment.elm
Normal file
@ -0,0 +1,343 @@
|
||||
module Comp.ItemDetail.SingleAttachment exposing (view)
|
||||
|
||||
import Api
|
||||
import Api.Model.Attachment exposing (Attachment)
|
||||
import Comp.AttachmentMeta
|
||||
import Comp.ItemDetail.Model
|
||||
exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, NotesField(..)
|
||||
, SaveNameState(..)
|
||||
)
|
||||
import Comp.MenuBar as MB
|
||||
import Comp.YesNoDimmer
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Dict
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick, onInput)
|
||||
import Html5.DragDrop as DD
|
||||
import Page exposing (Page(..))
|
||||
import Styles as S
|
||||
import Util.Maybe
|
||||
import Util.Size
|
||||
import Util.String
|
||||
|
||||
|
||||
view : UiSettings -> Model -> Int -> Attachment -> Html Msg
|
||||
view settings model pos attach =
|
||||
let
|
||||
fileUrl =
|
||||
Api.fileURL attach.id
|
||||
in
|
||||
div
|
||||
[ class "flex flex-col md:relative h-full mb-2"
|
||||
, classList
|
||||
[ ( "hidden", not (attachmentVisible model pos) )
|
||||
]
|
||||
]
|
||||
[ Html.map (DeleteAttachConfirm attach.id)
|
||||
(Comp.YesNoDimmer.viewN
|
||||
True
|
||||
(Comp.YesNoDimmer.defaultSettings2 "Really delete this file?")
|
||||
model.deleteAttachConfirm
|
||||
)
|
||||
, div
|
||||
[ class "flex flex-row px-2 py-2 text-sm"
|
||||
, class S.border
|
||||
]
|
||||
[ attachHeader settings model pos attach
|
||||
]
|
||||
, editAttachmentName model attach
|
||||
, attachmentSelect model pos attach
|
||||
, if isAttachMetaOpen model attach.id then
|
||||
case Dict.get attach.id model.attachMeta of
|
||||
Just am ->
|
||||
Html.map (AttachMetaMsg attach.id)
|
||||
(Comp.AttachmentMeta.view2 am)
|
||||
|
||||
Nothing ->
|
||||
span [ class "hidden" ] []
|
||||
|
||||
else
|
||||
div
|
||||
[ class "flex flex-col relative px-2 pt-2 h-full"
|
||||
, class "border-r border-l border-b dark:border-bluegray-600"
|
||||
, id "ds-pdf-view-parent"
|
||||
, style "max-height" "calc(100vh - 140px)"
|
||||
, style "min-height" "500px"
|
||||
]
|
||||
[ iframe
|
||||
[ if Maybe.withDefault settings.nativePdfPreview model.pdfNativeView then
|
||||
src fileUrl
|
||||
|
||||
else
|
||||
src (fileUrl ++ "/view")
|
||||
, class "absolute h-full w-full top-0 left-0 mx-0 py-0"
|
||||
, id "ds-pdf-view-iframe"
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
{-| attachment header
|
||||
|
||||
- toggle thumbs
|
||||
- name + size
|
||||
- eye icon to open it
|
||||
- menu
|
||||
- rename
|
||||
- meta data
|
||||
- download archive
|
||||
- download
|
||||
- delete
|
||||
- native view
|
||||
|
||||
-}
|
||||
attachHeader : UiSettings -> Model -> Int -> Attachment -> Html Msg
|
||||
attachHeader settings model _ attach =
|
||||
let
|
||||
attachName =
|
||||
Maybe.withDefault "No name" attach.name
|
||||
|
||||
fileUrl =
|
||||
Api.fileURL attach.id
|
||||
|
||||
hasArchive =
|
||||
List.map .id model.item.archives
|
||||
|> List.member attach.id
|
||||
|
||||
multiAttach =
|
||||
List.length model.item.attachments > 1
|
||||
|
||||
attachSelectToggle mobile =
|
||||
a
|
||||
[ href "#"
|
||||
, onClick ToggleAttachMenu
|
||||
, class S.secondaryBasicButton
|
||||
, classList
|
||||
[ ( "bg-gray-200 dark:bg-bluegray-600 ", model.attachMenuOpen )
|
||||
, ( "hidden", not multiAttach )
|
||||
, ( "sm:hidden", multiAttach && mobile )
|
||||
, ( "hidden sm:block", multiAttach && not mobile )
|
||||
]
|
||||
]
|
||||
[ i [ class "fa fa-images font-thin" ] []
|
||||
]
|
||||
in
|
||||
div [ class "flex flex-col sm:flex-row items-center w-full" ]
|
||||
[ attachSelectToggle False
|
||||
, div [ class "ml-2 text-base font-bold flex-grow w-full text-center sm:text-left" ]
|
||||
[ text attachName
|
||||
, text " ("
|
||||
, text (Util.Size.bytesReadable Util.Size.B (toFloat attach.size))
|
||||
, text ")"
|
||||
]
|
||||
, div [ class "flex flex-row justify-end items-center" ]
|
||||
[ attachSelectToggle True
|
||||
, a
|
||||
[ href fileUrl
|
||||
, target "_new"
|
||||
, title "Open file in new tab"
|
||||
, class S.secondaryBasicButton
|
||||
, class "ml-2"
|
||||
]
|
||||
[ i [ class "fa fa-eye font-thin" ] []
|
||||
]
|
||||
, MB.viewItem <|
|
||||
MB.Dropdown
|
||||
{ linkIcon = "fa fa-bars"
|
||||
, linkClass =
|
||||
[ ( "ml-2", True )
|
||||
, ( S.secondaryBasicButton, True )
|
||||
]
|
||||
, toggleMenu = ToggleAttachmentDropdown
|
||||
, menuOpen = model.attachmentDropdownOpen
|
||||
, items =
|
||||
[ { icon = "fa fa-download"
|
||||
, label = "Download file"
|
||||
, attrs =
|
||||
[ download attachName
|
||||
, href fileUrl
|
||||
]
|
||||
}
|
||||
, { icon = "fa fa-file"
|
||||
, label = "Rename file"
|
||||
, attrs =
|
||||
[ href "#"
|
||||
, onClick (EditAttachNameStart attach.id)
|
||||
]
|
||||
}
|
||||
, { icon = "fa fa-file-archive"
|
||||
, label = "Download original archive"
|
||||
, attrs =
|
||||
[ href (fileUrl ++ "/archive")
|
||||
, target "_new"
|
||||
, classList [ ( "hidden", not hasArchive ) ]
|
||||
]
|
||||
}
|
||||
, { icon = "fa fa-external-link-alt"
|
||||
, label = "Original file"
|
||||
, attrs =
|
||||
[ href (fileUrl ++ "/original")
|
||||
, target "_new"
|
||||
, classList [ ( "hidden", not attach.converted ) ]
|
||||
]
|
||||
}
|
||||
, { icon =
|
||||
if Maybe.withDefault settings.nativePdfPreview model.pdfNativeView then
|
||||
"fa fa-toggle-on"
|
||||
|
||||
else
|
||||
"fa fa-toggle-off"
|
||||
, label = "Render pdf by browser"
|
||||
, attrs =
|
||||
[ onClick (TogglePdfNativeView settings.nativePdfPreview)
|
||||
, href "#"
|
||||
]
|
||||
}
|
||||
, { icon =
|
||||
if isAttachMetaOpen model attach.id then
|
||||
"fa fa-toggle-on"
|
||||
|
||||
else
|
||||
"fa fa-toggle-off"
|
||||
, label = "View extracted data"
|
||||
, attrs =
|
||||
[ onClick (AttachMetaClick attach.id)
|
||||
, href "#"
|
||||
]
|
||||
}
|
||||
, { icon = "fa fa-trash"
|
||||
, label = "Delete this file"
|
||||
, attrs =
|
||||
[ onClick (RequestDeleteAttachment attach.id)
|
||||
, href "#"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
attachmentVisible : Model -> Int -> Bool
|
||||
attachmentVisible model pos =
|
||||
not model.sentMailsOpen
|
||||
&& (if model.visibleAttach >= List.length model.item.attachments then
|
||||
pos == 0
|
||||
|
||||
else
|
||||
model.visibleAttach == pos
|
||||
)
|
||||
|
||||
|
||||
isAttachMetaOpen : Model -> String -> Bool
|
||||
isAttachMetaOpen model id =
|
||||
model.attachMetaOpen && (Dict.get id model.attachMeta /= Nothing)
|
||||
|
||||
|
||||
editAttachmentName : Model -> Attachment -> Html Msg
|
||||
editAttachmentName model attach =
|
||||
let
|
||||
am =
|
||||
Util.Maybe.filter (\m -> m.id == attach.id) model.attachRename
|
||||
in
|
||||
case am of
|
||||
Just m ->
|
||||
div [ class "flex flex-row border-l border-r px-2 py-2 dark:border-bluegray-600" ]
|
||||
[ input
|
||||
[ type_ "text"
|
||||
, value m.newName
|
||||
, onInput EditAttachNameSet
|
||||
, class S.textInput
|
||||
, class "mr-2"
|
||||
]
|
||||
[]
|
||||
, button
|
||||
[ class S.primaryButton
|
||||
, onClick EditAttachNameSubmit
|
||||
]
|
||||
[ i [ class "fa fa-check" ] []
|
||||
]
|
||||
, button
|
||||
[ class S.secondaryButton
|
||||
, onClick EditAttachNameCancel
|
||||
]
|
||||
[ i [ class "fa fa-times" ] []
|
||||
]
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
span [ class "hidden" ] []
|
||||
|
||||
|
||||
attachmentSelect : Model -> Int -> Attachment -> Html Msg
|
||||
attachmentSelect model _ _ =
|
||||
div
|
||||
[ class "flex flex-row border-l border-r px-2 py-2 dark:border-bluegray-600 "
|
||||
, class "overflow-x-auto overflow-y-none"
|
||||
, classList
|
||||
[ ( "hidden", not model.attachMenuOpen )
|
||||
]
|
||||
]
|
||||
(List.indexedMap (menuItem model) model.item.attachments)
|
||||
|
||||
|
||||
menuItem : Model -> Int -> Attachment -> Html Msg
|
||||
menuItem model pos attach =
|
||||
let
|
||||
highlight =
|
||||
let
|
||||
dropId =
|
||||
DD.getDropId model.attachDD
|
||||
|
||||
dragId =
|
||||
DD.getDragId model.attachDD
|
||||
|
||||
enable =
|
||||
Just attach.id == dropId && dropId /= dragId
|
||||
in
|
||||
[ ( "bg-gray-300 dark:bg-bluegray-700 current-drop-target", enable )
|
||||
]
|
||||
|
||||
active =
|
||||
model.visibleAttach == pos
|
||||
in
|
||||
a
|
||||
([ classList <|
|
||||
[ ( "border-blue-500 dark:border-lightblue-500", pos == 0 )
|
||||
, ( "dark:border-bluegray-600", pos /= 0 )
|
||||
]
|
||||
++ highlight
|
||||
, class "block flex-col relative border rounded px-1 py-1 mr-2"
|
||||
, class " hover:shadow dark:hover:border-bluegray-500"
|
||||
, href "#"
|
||||
, onClick (SetActiveAttachment pos)
|
||||
]
|
||||
++ DD.draggable AttachDDMsg attach.id
|
||||
++ DD.droppable AttachDDMsg attach.id
|
||||
)
|
||||
[ div
|
||||
[ classList
|
||||
[ ( "hidden", not active )
|
||||
]
|
||||
, class "absolute right-1 top-1 text-blue-400 dark:text-lightblue-400 text-xl"
|
||||
]
|
||||
[ i [ class "fa fa-check-circle ml-1" ] []
|
||||
]
|
||||
, div [ class "" ]
|
||||
[ img
|
||||
[ src (Api.attachmentPreviewURL attach.id)
|
||||
, class "block w-20 mx-auto"
|
||||
]
|
||||
[]
|
||||
]
|
||||
, div [ class "mt-1 text-sm break-all w-28 text-center" ]
|
||||
[ Maybe.map (Util.String.ellipsis 36) attach.name
|
||||
|> Maybe.withDefault "No Name"
|
||||
|> text
|
||||
]
|
||||
]
|
Reference in New Issue
Block a user