mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-03-25 16:45:05 +00:00
Enhance item card displaying current file and number of pages
This commit is contained in:
parent
848c245db6
commit
7a14b05ea7
@ -6,6 +6,7 @@ module Api exposing
|
|||||||
, addMember
|
, addMember
|
||||||
, addTag
|
, addTag
|
||||||
, addTagsMultiple
|
, addTagsMultiple
|
||||||
|
, attachmentPreviewURL
|
||||||
, cancelJob
|
, cancelJob
|
||||||
, changeFolderName
|
, changeFolderName
|
||||||
, changePassword
|
, changePassword
|
||||||
@ -58,9 +59,9 @@ module Api exposing
|
|||||||
, getTagCloud
|
, getTagCloud
|
||||||
, getTags
|
, getTags
|
||||||
, getUsers
|
, getUsers
|
||||||
|
, itemBasePreviewURL
|
||||||
, itemDetail
|
, itemDetail
|
||||||
, itemIndexSearch
|
, itemIndexSearch
|
||||||
, itemPreviewURL
|
|
||||||
, itemSearch
|
, itemSearch
|
||||||
, login
|
, login
|
||||||
, loginSession
|
, loginSession
|
||||||
@ -1504,16 +1505,9 @@ deleteAllItems flags ids receive =
|
|||||||
--- Item
|
--- Item
|
||||||
|
|
||||||
|
|
||||||
itemPreviewURL : ItemLight -> String
|
attachmentPreviewURL : String -> String
|
||||||
itemPreviewURL item =
|
attachmentPreviewURL id =
|
||||||
let
|
"/api/v1/sec/attachment/" ++ id ++ "/preview?withFallback=true"
|
||||||
makeUrl a =
|
|
||||||
"/api/v1/sec/attachment/" ++ a.id ++ "/preview?withFallback=true"
|
|
||||||
in
|
|
||||||
List.sortBy .position item.attachments
|
|
||||||
|> List.head
|
|
||||||
|> Maybe.map makeUrl
|
|
||||||
|> Maybe.withDefault (itemBasePreviewURL item.id)
|
|
||||||
|
|
||||||
|
|
||||||
itemBasePreviewURL : String -> String
|
itemBasePreviewURL : String -> String
|
||||||
|
442
modules/webapp/src/main/elm/Comp/ItemCard.elm
Normal file
442
modules/webapp/src/main/elm/Comp/ItemCard.elm
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
module Comp.ItemCard exposing (..)
|
||||||
|
|
||||||
|
import Api
|
||||||
|
import Api.Model.AttachmentLight exposing (AttachmentLight)
|
||||||
|
import Api.Model.HighlightEntry exposing (HighlightEntry)
|
||||||
|
import Api.Model.ItemLight exposing (ItemLight)
|
||||||
|
import Data.Direction
|
||||||
|
import Data.Fields
|
||||||
|
import Data.Icons as Icons
|
||||||
|
import Data.ItemSelection exposing (ItemSelection)
|
||||||
|
import Data.UiSettings exposing (UiSettings)
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes exposing (..)
|
||||||
|
import Html.Events exposing (onClick)
|
||||||
|
import Markdown
|
||||||
|
import Page exposing (Page(..))
|
||||||
|
import Set exposing (Set)
|
||||||
|
import Util.Html
|
||||||
|
import Util.ItemDragDrop as DD
|
||||||
|
import Util.List
|
||||||
|
import Util.Maybe
|
||||||
|
import Util.String
|
||||||
|
import Util.Time
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ previewAttach : Maybe AttachmentLight
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= CyclePreview ItemLight
|
||||||
|
| ToggleSelectItem (Set String) String
|
||||||
|
| ItemDDMsg DD.Msg
|
||||||
|
|
||||||
|
|
||||||
|
type alias ViewConfig =
|
||||||
|
{ selection : ItemSelection
|
||||||
|
, extraClasses : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias UpdateResult =
|
||||||
|
{ model : Model
|
||||||
|
, dragModel : DD.Model
|
||||||
|
, selection : ItemSelection
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init : Model
|
||||||
|
init =
|
||||||
|
{ previewAttach = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
currentAttachment : Model -> ItemLight -> Maybe AttachmentLight
|
||||||
|
currentAttachment model item =
|
||||||
|
Util.Maybe.or
|
||||||
|
[ model.previewAttach
|
||||||
|
, List.head item.attachments
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
currentPosition : Model -> ItemLight -> Int
|
||||||
|
currentPosition model item =
|
||||||
|
let
|
||||||
|
filter cur el =
|
||||||
|
cur.id == el.id
|
||||||
|
in
|
||||||
|
case model.previewAttach of
|
||||||
|
Just a ->
|
||||||
|
case Util.List.findIndexed (filter a) item.attachments of
|
||||||
|
Just ( _, n ) ->
|
||||||
|
n + 1
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
1
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
1
|
||||||
|
|
||||||
|
|
||||||
|
update : DD.Model -> Msg -> Model -> UpdateResult
|
||||||
|
update ddm msg model =
|
||||||
|
case msg of
|
||||||
|
ItemDDMsg lm ->
|
||||||
|
let
|
||||||
|
ddd =
|
||||||
|
DD.update lm ddm
|
||||||
|
in
|
||||||
|
UpdateResult model ddd.model Data.ItemSelection.Inactive
|
||||||
|
|
||||||
|
ToggleSelectItem ids id ->
|
||||||
|
let
|
||||||
|
newSet =
|
||||||
|
if Set.member id ids then
|
||||||
|
Set.remove id ids
|
||||||
|
|
||||||
|
else
|
||||||
|
Set.insert id ids
|
||||||
|
in
|
||||||
|
UpdateResult model ddm (Data.ItemSelection.Active newSet)
|
||||||
|
|
||||||
|
CyclePreview item ->
|
||||||
|
let
|
||||||
|
mainAttach =
|
||||||
|
currentAttachment model item
|
||||||
|
|
||||||
|
next =
|
||||||
|
Util.List.findNext (\e -> Just e.id == Maybe.map .id mainAttach) item.attachments
|
||||||
|
in
|
||||||
|
UpdateResult { model | previewAttach = next }
|
||||||
|
ddm
|
||||||
|
Data.ItemSelection.Inactive
|
||||||
|
|
||||||
|
|
||||||
|
view : ViewConfig -> UiSettings -> Model -> ItemLight -> Html Msg
|
||||||
|
view cfg settings model item =
|
||||||
|
let
|
||||||
|
dirIcon =
|
||||||
|
i [ class (Data.Direction.iconFromMaybe item.direction) ] []
|
||||||
|
|
||||||
|
corr =
|
||||||
|
List.filterMap identity [ item.corrOrg, item.corrPerson ]
|
||||||
|
|> List.map .name
|
||||||
|
|> List.intersperse ", "
|
||||||
|
|> String.concat
|
||||||
|
|
||||||
|
conc =
|
||||||
|
List.filterMap identity [ item.concPerson, item.concEquip ]
|
||||||
|
|> List.map .name
|
||||||
|
|> List.intersperse ", "
|
||||||
|
|> String.concat
|
||||||
|
|
||||||
|
folder =
|
||||||
|
Maybe.map .name item.folder
|
||||||
|
|> Maybe.withDefault ""
|
||||||
|
|
||||||
|
dueDate =
|
||||||
|
Maybe.map Util.Time.formatDateShort item.dueDate
|
||||||
|
|> Maybe.withDefault ""
|
||||||
|
|
||||||
|
isConfirmed =
|
||||||
|
item.state /= "created"
|
||||||
|
|
||||||
|
cardColor =
|
||||||
|
if isSelected cfg item.id then
|
||||||
|
"purple"
|
||||||
|
|
||||||
|
else if not isConfirmed then
|
||||||
|
"blue"
|
||||||
|
|
||||||
|
else
|
||||||
|
""
|
||||||
|
|
||||||
|
fieldHidden f =
|
||||||
|
Data.UiSettings.fieldHidden settings f
|
||||||
|
|
||||||
|
cardAction =
|
||||||
|
case cfg.selection of
|
||||||
|
Data.ItemSelection.Inactive ->
|
||||||
|
Page.href (ItemDetailPage item.id)
|
||||||
|
|
||||||
|
Data.ItemSelection.Active ids ->
|
||||||
|
onClick (ToggleSelectItem ids item.id)
|
||||||
|
|
||||||
|
mainAttach =
|
||||||
|
currentAttachment model item
|
||||||
|
|
||||||
|
previewUrl =
|
||||||
|
Maybe.map .id mainAttach
|
||||||
|
|> Maybe.map Api.attachmentPreviewURL
|
||||||
|
|> Maybe.withDefault (Api.itemBasePreviewURL item.id)
|
||||||
|
|
||||||
|
pageCount =
|
||||||
|
Maybe.andThen .pageCount mainAttach
|
||||||
|
|> Maybe.withDefault 0
|
||||||
|
|
||||||
|
pageCountLabel =
|
||||||
|
div
|
||||||
|
[ classList
|
||||||
|
[ ( "card-attachment-nav", True )
|
||||||
|
, ( "invisible", pageCount == 0 )
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ if item.fileCount == 1 then
|
||||||
|
div
|
||||||
|
[ class "ui secondary basic mini label"
|
||||||
|
, title "Number of pages"
|
||||||
|
]
|
||||||
|
[ text "p."
|
||||||
|
, text (String.fromInt pageCount)
|
||||||
|
]
|
||||||
|
|
||||||
|
else
|
||||||
|
div [ class "ui left labeled mini button" ]
|
||||||
|
[ div [ class "ui basic right pointing mini label" ]
|
||||||
|
[ currentPosition model item
|
||||||
|
|> String.fromInt
|
||||||
|
|> text
|
||||||
|
, text "/"
|
||||||
|
, text (String.fromInt item.fileCount)
|
||||||
|
, text " p."
|
||||||
|
, text (String.fromInt pageCount)
|
||||||
|
]
|
||||||
|
, a
|
||||||
|
[ class "ui mini icon secondary button"
|
||||||
|
, href "#"
|
||||||
|
, onClick (CyclePreview item)
|
||||||
|
]
|
||||||
|
[ i [ class "arrow right icon" ] []
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
in
|
||||||
|
div
|
||||||
|
([ classList
|
||||||
|
[ ( "ui fluid card", True )
|
||||||
|
, ( cardColor, True )
|
||||||
|
, ( cfg.extraClasses, True )
|
||||||
|
]
|
||||||
|
, id item.id
|
||||||
|
]
|
||||||
|
++ DD.draggable ItemDDMsg item.id
|
||||||
|
)
|
||||||
|
[ if fieldHidden Data.Fields.PreviewImage then
|
||||||
|
span [ class "invisible" ] []
|
||||||
|
|
||||||
|
else
|
||||||
|
div [ class "image" ]
|
||||||
|
[ img
|
||||||
|
[ class "preview-image"
|
||||||
|
, src previewUrl
|
||||||
|
, Data.UiSettings.cardPreviewSize settings
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
, pageCountLabel
|
||||||
|
]
|
||||||
|
, a
|
||||||
|
[ class "link content"
|
||||||
|
, href "#"
|
||||||
|
, cardAction
|
||||||
|
]
|
||||||
|
[ case cfg.selection of
|
||||||
|
Data.ItemSelection.Active ids ->
|
||||||
|
div [ class "header" ]
|
||||||
|
[ Util.Html.checkbox (Set.member item.id ids)
|
||||||
|
, dirIcon
|
||||||
|
, Util.String.underscoreToSpace item.name
|
||||||
|
|> text
|
||||||
|
]
|
||||||
|
|
||||||
|
Data.ItemSelection.Inactive ->
|
||||||
|
if fieldHidden Data.Fields.Direction then
|
||||||
|
div [ class "header" ]
|
||||||
|
[ Util.String.underscoreToSpace item.name |> text
|
||||||
|
]
|
||||||
|
|
||||||
|
else
|
||||||
|
div
|
||||||
|
[ class "header"
|
||||||
|
, Data.Direction.labelFromMaybe item.direction
|
||||||
|
|> title
|
||||||
|
]
|
||||||
|
[ dirIcon
|
||||||
|
, Util.String.underscoreToSpace item.name
|
||||||
|
|> text
|
||||||
|
]
|
||||||
|
, div
|
||||||
|
[ classList
|
||||||
|
[ ( "ui right corner label", True )
|
||||||
|
, ( cardColor, True )
|
||||||
|
, ( "invisible", isConfirmed )
|
||||||
|
]
|
||||||
|
, title "New"
|
||||||
|
]
|
||||||
|
[ i [ class "exclamation icon" ] []
|
||||||
|
]
|
||||||
|
, div
|
||||||
|
[ classList
|
||||||
|
[ ( "meta", True )
|
||||||
|
, ( "invisible hidden", fieldHidden Data.Fields.Date )
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ Util.Time.formatDate item.date |> text
|
||||||
|
]
|
||||||
|
, div [ class "meta description" ]
|
||||||
|
[ div
|
||||||
|
[ classList
|
||||||
|
[ ( "ui right floated tiny labels", True )
|
||||||
|
, ( "invisible hidden", item.tags == [] || fieldHidden Data.Fields.Tag )
|
||||||
|
]
|
||||||
|
]
|
||||||
|
(List.map
|
||||||
|
(\tag ->
|
||||||
|
div
|
||||||
|
[ classList
|
||||||
|
[ ( "ui basic label", True )
|
||||||
|
, ( Data.UiSettings.tagColorString tag settings, True )
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ text tag.name ]
|
||||||
|
)
|
||||||
|
item.tags
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, div
|
||||||
|
[ classList
|
||||||
|
[ ( "content", True )
|
||||||
|
, ( "invisible hidden"
|
||||||
|
, settings.itemSearchNoteLength
|
||||||
|
<= 0
|
||||||
|
|| Util.String.isNothingOrBlank item.notes
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ span [ class "small-info" ]
|
||||||
|
[ Maybe.withDefault "" item.notes
|
||||||
|
|> Util.String.ellipsis settings.itemSearchNoteLength
|
||||||
|
|> text
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, div [ class "content" ]
|
||||||
|
[ div [ class "ui horizontal list" ]
|
||||||
|
[ div
|
||||||
|
[ classList
|
||||||
|
[ ( "item", True )
|
||||||
|
, ( "invisible hidden"
|
||||||
|
, fieldHidden Data.Fields.CorrOrg
|
||||||
|
&& fieldHidden Data.Fields.CorrPerson
|
||||||
|
)
|
||||||
|
]
|
||||||
|
, title "Correspondent"
|
||||||
|
]
|
||||||
|
[ Icons.correspondentIcon ""
|
||||||
|
, text " "
|
||||||
|
, Util.String.withDefault "-" corr |> text
|
||||||
|
]
|
||||||
|
, div
|
||||||
|
[ classList
|
||||||
|
[ ( "item", True )
|
||||||
|
, ( "invisible hidden"
|
||||||
|
, fieldHidden Data.Fields.ConcPerson
|
||||||
|
&& fieldHidden Data.Fields.ConcEquip
|
||||||
|
)
|
||||||
|
]
|
||||||
|
, title "Concerning"
|
||||||
|
]
|
||||||
|
[ Icons.concernedIcon
|
||||||
|
, text " "
|
||||||
|
, Util.String.withDefault "-" conc |> text
|
||||||
|
]
|
||||||
|
, div
|
||||||
|
[ classList
|
||||||
|
[ ( "item", True )
|
||||||
|
, ( "invisible hidden", fieldHidden Data.Fields.Folder )
|
||||||
|
]
|
||||||
|
, title "Folder"
|
||||||
|
]
|
||||||
|
[ Icons.folderIcon ""
|
||||||
|
, text " "
|
||||||
|
, Util.String.withDefault "-" folder |> text
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, div [ class "right floated meta" ]
|
||||||
|
[ div [ class "ui horizontal list" ]
|
||||||
|
[ div
|
||||||
|
[ class "item"
|
||||||
|
, title "Source"
|
||||||
|
]
|
||||||
|
[ text item.source
|
||||||
|
]
|
||||||
|
, div
|
||||||
|
[ classList
|
||||||
|
[ ( "item", True )
|
||||||
|
, ( "invisible hidden"
|
||||||
|
, item.dueDate
|
||||||
|
== Nothing
|
||||||
|
|| fieldHidden Data.Fields.DueDate
|
||||||
|
)
|
||||||
|
]
|
||||||
|
, title ("Due on " ++ dueDate)
|
||||||
|
]
|
||||||
|
[ div
|
||||||
|
[ class "ui basic grey label"
|
||||||
|
]
|
||||||
|
[ Icons.dueDateIcon ""
|
||||||
|
, text (" " ++ dueDate)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, div
|
||||||
|
[ classList
|
||||||
|
[ ( "content search-highlight", True )
|
||||||
|
, ( "invisible hidden", item.highlighting == [] )
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ div [ class "ui list" ]
|
||||||
|
(List.map renderHighlightEntry item.highlighting)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
renderHighlightEntry : HighlightEntry -> Html Msg
|
||||||
|
renderHighlightEntry entry =
|
||||||
|
let
|
||||||
|
stripWhitespace str =
|
||||||
|
String.trim str
|
||||||
|
|> String.replace "```" ""
|
||||||
|
|> String.replace "\t" " "
|
||||||
|
|> String.replace "\n\n" "\n"
|
||||||
|
|> String.lines
|
||||||
|
|> List.map String.trim
|
||||||
|
|> String.join "\n"
|
||||||
|
in
|
||||||
|
div [ class "item" ]
|
||||||
|
[ div [ class "content" ]
|
||||||
|
(div [ class "header" ]
|
||||||
|
[ i [ class "caret right icon" ] []
|
||||||
|
, text (entry.name ++ ":")
|
||||||
|
]
|
||||||
|
:: List.map
|
||||||
|
(\str ->
|
||||||
|
Markdown.toHtml [ class "description" ] <|
|
||||||
|
(stripWhitespace str ++ "…")
|
||||||
|
)
|
||||||
|
entry.lines
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
isSelected : ViewConfig -> String -> Bool
|
||||||
|
isSelected cfg id =
|
||||||
|
case cfg.selection of
|
||||||
|
Data.ItemSelection.Active ids ->
|
||||||
|
Set.member id ids
|
||||||
|
|
||||||
|
Data.ItemSelection.Inactive ->
|
||||||
|
False
|
@ -10,46 +10,38 @@ module Comp.ItemCardList exposing
|
|||||||
, view
|
, view
|
||||||
)
|
)
|
||||||
|
|
||||||
import Api
|
|
||||||
import Api.Model.HighlightEntry exposing (HighlightEntry)
|
|
||||||
import Api.Model.ItemLight exposing (ItemLight)
|
import Api.Model.ItemLight exposing (ItemLight)
|
||||||
import Api.Model.ItemLightGroup exposing (ItemLightGroup)
|
import Api.Model.ItemLightGroup exposing (ItemLightGroup)
|
||||||
import Api.Model.ItemLightList exposing (ItemLightList)
|
import Api.Model.ItemLightList exposing (ItemLightList)
|
||||||
import Data.Direction
|
import Comp.ItemCard
|
||||||
import Data.Fields
|
|
||||||
import Data.Flags exposing (Flags)
|
import Data.Flags exposing (Flags)
|
||||||
import Data.Icons as Icons
|
|
||||||
import Data.ItemSelection exposing (ItemSelection)
|
import Data.ItemSelection exposing (ItemSelection)
|
||||||
import Data.Items
|
import Data.Items
|
||||||
import Data.UiSettings exposing (UiSettings)
|
import Data.UiSettings exposing (UiSettings)
|
||||||
|
import Dict exposing (Dict)
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
import Html.Events exposing (onClick)
|
|
||||||
import Markdown
|
|
||||||
import Page exposing (Page(..))
|
import Page exposing (Page(..))
|
||||||
import Set exposing (Set)
|
|
||||||
import Util.Html
|
|
||||||
import Util.ItemDragDrop as DD
|
import Util.ItemDragDrop as DD
|
||||||
import Util.List
|
import Util.List
|
||||||
import Util.String
|
|
||||||
import Util.Time
|
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ results : ItemLightList
|
{ results : ItemLightList
|
||||||
|
, itemCards : Dict String Comp.ItemCard.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
type Msg
|
||||||
= SetResults ItemLightList
|
= SetResults ItemLightList
|
||||||
| AddResults ItemLightList
|
| AddResults ItemLightList
|
||||||
| ItemDDMsg DD.Msg
|
| ItemCardMsg ItemLight Comp.ItemCard.Msg
|
||||||
| ToggleSelectItem (Set String) String
|
|
||||||
|
|
||||||
|
|
||||||
init : Model
|
init : Model
|
||||||
init =
|
init =
|
||||||
{ results = Api.Model.ItemLightList.empty
|
{ results = Api.Model.ItemLightList.empty
|
||||||
|
, itemCards = Dict.empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -112,23 +104,22 @@ updateDrag dm _ msg model =
|
|||||||
in
|
in
|
||||||
UpdateResult newModel Cmd.none dm Data.ItemSelection.Inactive
|
UpdateResult newModel Cmd.none dm Data.ItemSelection.Inactive
|
||||||
|
|
||||||
ItemDDMsg lm ->
|
ItemCardMsg item lm ->
|
||||||
let
|
let
|
||||||
ddd =
|
cardModel =
|
||||||
DD.update lm dm
|
Dict.get item.id model.itemCards
|
||||||
in
|
|> Maybe.withDefault Comp.ItemCard.init
|
||||||
UpdateResult model Cmd.none ddd.model Data.ItemSelection.Inactive
|
|
||||||
|
|
||||||
ToggleSelectItem ids id ->
|
result =
|
||||||
let
|
Comp.ItemCard.update dm lm cardModel
|
||||||
newSet =
|
|
||||||
if Set.member id ids then
|
|
||||||
Set.remove id ids
|
|
||||||
|
|
||||||
else
|
cards =
|
||||||
Set.insert id ids
|
Dict.insert item.id result.model model.itemCards
|
||||||
in
|
in
|
||||||
UpdateResult model Cmd.none dm (Data.ItemSelection.Active newSet)
|
UpdateResult { model | itemCards = cards }
|
||||||
|
Cmd.none
|
||||||
|
result.dragModel
|
||||||
|
result.selection
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -141,297 +132,42 @@ type alias ViewConfig =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
isSelected : ViewConfig -> String -> Bool
|
|
||||||
isSelected cfg id =
|
|
||||||
case cfg.selection of
|
|
||||||
Data.ItemSelection.Active ids ->
|
|
||||||
Set.member id ids
|
|
||||||
|
|
||||||
Data.ItemSelection.Inactive ->
|
|
||||||
False
|
|
||||||
|
|
||||||
|
|
||||||
view : ViewConfig -> UiSettings -> Model -> Html Msg
|
view : ViewConfig -> UiSettings -> Model -> Html Msg
|
||||||
view cfg settings model =
|
view cfg settings model =
|
||||||
div [ class "ui container" ]
|
div [ class "ui container" ]
|
||||||
(List.map (viewGroup cfg settings) model.results.groups)
|
(List.map (viewGroup model cfg settings) model.results.groups)
|
||||||
|
|
||||||
|
|
||||||
viewGroup : ViewConfig -> UiSettings -> ItemLightGroup -> Html Msg
|
viewGroup : Model -> ViewConfig -> UiSettings -> ItemLightGroup -> Html Msg
|
||||||
viewGroup cfg settings group =
|
viewGroup model cfg settings group =
|
||||||
div [ class "item-group" ]
|
div [ class "item-group" ]
|
||||||
[ div [ class "ui horizontal divider header item-list" ]
|
[ div [ class "ui horizontal divider header item-list" ]
|
||||||
[ i [ class "calendar alternate outline icon" ] []
|
[ i [ class "calendar alternate outline icon" ] []
|
||||||
, text group.name
|
, text group.name
|
||||||
]
|
]
|
||||||
, div [ class "ui stackable three cards" ]
|
, div [ class "ui stackable three cards" ]
|
||||||
(List.map (viewItem cfg settings) group.items)
|
(List.map (viewItem model cfg settings) group.items)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
viewItem : ViewConfig -> UiSettings -> ItemLight -> Html Msg
|
viewItem : Model -> ViewConfig -> UiSettings -> ItemLight -> Html Msg
|
||||||
viewItem cfg settings item =
|
viewItem model cfg settings item =
|
||||||
let
|
let
|
||||||
dirIcon =
|
currentClass =
|
||||||
i [ class (Data.Direction.iconFromMaybe item.direction) ] []
|
if cfg.current == Just item.id then
|
||||||
|
"current"
|
||||||
corr =
|
|
||||||
List.filterMap identity [ item.corrOrg, item.corrPerson ]
|
|
||||||
|> List.map .name
|
|
||||||
|> List.intersperse ", "
|
|
||||||
|> String.concat
|
|
||||||
|
|
||||||
conc =
|
|
||||||
List.filterMap identity [ item.concPerson, item.concEquip ]
|
|
||||||
|> List.map .name
|
|
||||||
|> List.intersperse ", "
|
|
||||||
|> String.concat
|
|
||||||
|
|
||||||
folder =
|
|
||||||
Maybe.map .name item.folder
|
|
||||||
|> Maybe.withDefault ""
|
|
||||||
|
|
||||||
dueDate =
|
|
||||||
Maybe.map Util.Time.formatDateShort item.dueDate
|
|
||||||
|> Maybe.withDefault ""
|
|
||||||
|
|
||||||
isConfirmed =
|
|
||||||
item.state /= "created"
|
|
||||||
|
|
||||||
cardColor =
|
|
||||||
if isSelected cfg item.id then
|
|
||||||
"purple"
|
|
||||||
|
|
||||||
else if not isConfirmed then
|
|
||||||
"blue"
|
|
||||||
|
|
||||||
else
|
else
|
||||||
""
|
""
|
||||||
|
|
||||||
fieldHidden f =
|
vvcfg =
|
||||||
Data.UiSettings.fieldHidden settings f
|
Comp.ItemCard.ViewConfig cfg.selection currentClass
|
||||||
|
|
||||||
cardAction =
|
cardModel =
|
||||||
case cfg.selection of
|
Dict.get item.id model.itemCards
|
||||||
Data.ItemSelection.Inactive ->
|
|> Maybe.withDefault Comp.ItemCard.init
|
||||||
Page.href (ItemDetailPage item.id)
|
|
||||||
|
|
||||||
Data.ItemSelection.Active ids ->
|
cardHtml =
|
||||||
onClick (ToggleSelectItem ids item.id)
|
Comp.ItemCard.view vvcfg settings cardModel item
|
||||||
in
|
in
|
||||||
div
|
Html.map (ItemCardMsg item) cardHtml
|
||||||
([ classList
|
|
||||||
[ ( "ui fluid card", True )
|
|
||||||
, ( cardColor, True )
|
|
||||||
, ( "current", cfg.current == Just item.id )
|
|
||||||
]
|
|
||||||
, id item.id
|
|
||||||
]
|
|
||||||
++ DD.draggable ItemDDMsg item.id
|
|
||||||
)
|
|
||||||
[ if fieldHidden Data.Fields.PreviewImage then
|
|
||||||
span [ class "invisible" ] []
|
|
||||||
|
|
||||||
else
|
|
||||||
div [ class "image" ]
|
|
||||||
[ img
|
|
||||||
[ class "preview-image"
|
|
||||||
, src (Api.itemPreviewURL item)
|
|
||||||
, Data.UiSettings.cardPreviewSize settings
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
, a
|
|
||||||
[ class "content"
|
|
||||||
, href "#"
|
|
||||||
, cardAction
|
|
||||||
]
|
|
||||||
[ case cfg.selection of
|
|
||||||
Data.ItemSelection.Active ids ->
|
|
||||||
div [ class "header" ]
|
|
||||||
[ Util.Html.checkbox (Set.member item.id ids)
|
|
||||||
, dirIcon
|
|
||||||
, Util.String.underscoreToSpace item.name
|
|
||||||
|> text
|
|
||||||
]
|
|
||||||
|
|
||||||
Data.ItemSelection.Inactive ->
|
|
||||||
if fieldHidden Data.Fields.Direction then
|
|
||||||
div [ class "header" ]
|
|
||||||
[ Util.String.underscoreToSpace item.name |> text
|
|
||||||
]
|
|
||||||
|
|
||||||
else
|
|
||||||
div
|
|
||||||
[ class "header"
|
|
||||||
, Data.Direction.labelFromMaybe item.direction
|
|
||||||
|> title
|
|
||||||
]
|
|
||||||
[ dirIcon
|
|
||||||
, Util.String.underscoreToSpace item.name
|
|
||||||
|> text
|
|
||||||
]
|
|
||||||
, div
|
|
||||||
[ classList
|
|
||||||
[ ( "ui right corner label", True )
|
|
||||||
, ( cardColor, True )
|
|
||||||
, ( "invisible", isConfirmed )
|
|
||||||
]
|
|
||||||
, title "New"
|
|
||||||
]
|
|
||||||
[ i [ class "exclamation icon" ] []
|
|
||||||
]
|
|
||||||
, div
|
|
||||||
[ classList
|
|
||||||
[ ( "meta", True )
|
|
||||||
, ( "invisible hidden", fieldHidden Data.Fields.Date )
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ Util.Time.formatDate item.date |> text
|
|
||||||
]
|
|
||||||
, div [ class "meta description" ]
|
|
||||||
[ div
|
|
||||||
[ classList
|
|
||||||
[ ( "ui right floated tiny labels", True )
|
|
||||||
, ( "invisible hidden", item.tags == [] || fieldHidden Data.Fields.Tag )
|
|
||||||
]
|
|
||||||
]
|
|
||||||
(List.map
|
|
||||||
(\tag ->
|
|
||||||
div
|
|
||||||
[ classList
|
|
||||||
[ ( "ui basic label", True )
|
|
||||||
, ( Data.UiSettings.tagColorString tag settings, True )
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ text tag.name ]
|
|
||||||
)
|
|
||||||
item.tags
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, div
|
|
||||||
[ classList
|
|
||||||
[ ( "content", True )
|
|
||||||
, ( "invisible hidden"
|
|
||||||
, settings.itemSearchNoteLength
|
|
||||||
<= 0
|
|
||||||
|| Util.String.isNothingOrBlank item.notes
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ span [ class "small-info" ]
|
|
||||||
[ Maybe.withDefault "" item.notes
|
|
||||||
|> Util.String.ellipsis settings.itemSearchNoteLength
|
|
||||||
|> text
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, div [ class "content" ]
|
|
||||||
[ div [ class "ui horizontal list" ]
|
|
||||||
[ div
|
|
||||||
[ classList
|
|
||||||
[ ( "item", True )
|
|
||||||
, ( "invisible hidden"
|
|
||||||
, fieldHidden Data.Fields.CorrOrg
|
|
||||||
&& fieldHidden Data.Fields.CorrPerson
|
|
||||||
)
|
|
||||||
]
|
|
||||||
, title "Correspondent"
|
|
||||||
]
|
|
||||||
[ Icons.correspondentIcon ""
|
|
||||||
, text " "
|
|
||||||
, Util.String.withDefault "-" corr |> text
|
|
||||||
]
|
|
||||||
, div
|
|
||||||
[ classList
|
|
||||||
[ ( "item", True )
|
|
||||||
, ( "invisible hidden"
|
|
||||||
, fieldHidden Data.Fields.ConcPerson
|
|
||||||
&& fieldHidden Data.Fields.ConcEquip
|
|
||||||
)
|
|
||||||
]
|
|
||||||
, title "Concerning"
|
|
||||||
]
|
|
||||||
[ Icons.concernedIcon
|
|
||||||
, text " "
|
|
||||||
, Util.String.withDefault "-" conc |> text
|
|
||||||
]
|
|
||||||
, div
|
|
||||||
[ classList
|
|
||||||
[ ( "item", True )
|
|
||||||
, ( "invisible hidden", fieldHidden Data.Fields.Folder )
|
|
||||||
]
|
|
||||||
, title "Folder"
|
|
||||||
]
|
|
||||||
[ Icons.folderIcon ""
|
|
||||||
, text " "
|
|
||||||
, Util.String.withDefault "-" folder |> text
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, div [ class "right floated meta" ]
|
|
||||||
[ div [ class "ui horizontal list" ]
|
|
||||||
[ div
|
|
||||||
[ class "item"
|
|
||||||
, title "Source"
|
|
||||||
]
|
|
||||||
[ text item.source
|
|
||||||
]
|
|
||||||
, div
|
|
||||||
[ classList
|
|
||||||
[ ( "item", True )
|
|
||||||
, ( "invisible hidden"
|
|
||||||
, item.dueDate
|
|
||||||
== Nothing
|
|
||||||
|| fieldHidden Data.Fields.DueDate
|
|
||||||
)
|
|
||||||
]
|
|
||||||
, title ("Due on " ++ dueDate)
|
|
||||||
]
|
|
||||||
[ div
|
|
||||||
[ class "ui basic grey label"
|
|
||||||
]
|
|
||||||
[ Icons.dueDateIcon ""
|
|
||||||
, text (" " ++ dueDate)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, div
|
|
||||||
[ classList
|
|
||||||
[ ( "content search-highlight", True )
|
|
||||||
, ( "invisible hidden", item.highlighting == [] )
|
|
||||||
]
|
|
||||||
]
|
|
||||||
[ div [ class "ui list" ]
|
|
||||||
(List.map renderHighlightEntry item.highlighting)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
renderHighlightEntry : HighlightEntry -> Html Msg
|
|
||||||
renderHighlightEntry entry =
|
|
||||||
let
|
|
||||||
stripWhitespace str =
|
|
||||||
String.trim str
|
|
||||||
|> String.replace "```" ""
|
|
||||||
|> String.replace "\t" " "
|
|
||||||
|> String.replace "\n\n" "\n"
|
|
||||||
|> String.lines
|
|
||||||
|> List.map String.trim
|
|
||||||
|> String.join "\n"
|
|
||||||
in
|
|
||||||
div [ class "item" ]
|
|
||||||
[ div [ class "content" ]
|
|
||||||
(div [ class "header" ]
|
|
||||||
[ i [ class "caret right icon" ] []
|
|
||||||
, text (entry.name ++ ":")
|
|
||||||
]
|
|
||||||
:: List.map
|
|
||||||
(\str ->
|
|
||||||
Markdown.toHtml [ class "description" ] <|
|
|
||||||
(stripWhitespace str ++ "…")
|
|
||||||
)
|
|
||||||
entry.lines
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
@ -92,7 +92,15 @@
|
|||||||
background: floralwhite;
|
background: floralwhite;
|
||||||
padding: 0.8em;
|
padding: 0.8em;
|
||||||
}
|
}
|
||||||
|
.default-layout .ui.card .link.content:hover {
|
||||||
|
box-shadow: 0 0 0 1px #d4d4d5,0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.15);
|
||||||
|
}
|
||||||
|
.default-layout .image .card-attachment-nav {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 2px;
|
||||||
|
right: 2px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
.default-layout img.preview-image {
|
.default-layout img.preview-image {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
@ -119,7 +127,6 @@
|
|||||||
background: rgba(220, 255, 71, 0.6);
|
background: rgba(220, 255, 71, 0.6);
|
||||||
}
|
}
|
||||||
.default-layout .ui.cards .ui.card.current {
|
.default-layout .ui.cards .ui.card.current {
|
||||||
/* semantic-ui purple */
|
|
||||||
box-shadow: 0 0 6px rgba(0,0,0,0.55);
|
box-shadow: 0 0 6px rgba(0,0,0,0.55);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user