Merge pull request #124 from eikek/item-list

Item list
This commit is contained in:
eikek
2020-05-17 22:30:45 +02:00
committed by GitHub
15 changed files with 337 additions and 26 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 108 KiB

View File

@ -0,0 +1,199 @@
module Comp.ItemCardList exposing
( Model
, Msg(..)
, init
, nextItem
, prevItem
, update
, view
)
import Api.Model.ItemLight exposing (ItemLight)
import Api.Model.ItemLightGroup exposing (ItemLightGroup)
import Api.Model.ItemLightList exposing (ItemLightList)
import Data.Direction
import Data.Flags exposing (Flags)
import Data.Icons as Icons
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
import Util.List
import Util.String
import Util.Time
type alias Model =
{ results : ItemLightList
}
type Msg
= SetResults ItemLightList
| SelectItem ItemLight
init : Model
init =
{ results = Api.Model.ItemLightList.empty
}
nextItem : Model -> String -> Maybe ItemLight
nextItem model id =
List.concatMap .items model.results.groups
|> Util.List.findNext (\i -> i.id == id)
prevItem : Model -> String -> Maybe ItemLight
prevItem model id =
List.concatMap .items model.results.groups
|> Util.List.findPrev (\i -> i.id == id)
--- Update
update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Maybe ItemLight )
update _ msg model =
case msg of
SetResults list ->
let
newModel =
{ model | results = list }
in
( newModel, Cmd.none, Nothing )
SelectItem item ->
( model, Cmd.none, Just item )
--- View
view : Model -> Html Msg
view model =
div [ class "ui container" ]
(List.map viewGroup model.results.groups)
viewGroup : ItemLightGroup -> Html Msg
viewGroup group =
div [ class "item-group" ]
[ div [ class "ui horizontal divider header item-list" ]
[ i [ class "calendar alternate outline icon" ] []
, text group.name
]
, div [ class "ui stackable three cards" ]
(List.map viewItem group.items)
]
viewItem : ItemLight -> Html Msg
viewItem 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
dueDate =
Maybe.map Util.Time.formatDateShort item.dueDate
|> Maybe.withDefault ""
isConfirmed =
item.state /= "created"
newColor =
"blue"
in
a
[ classList
[ ( "ui fluid card", True )
, ( newColor, not isConfirmed )
]
, href "#"
, onClick (SelectItem item)
]
[ div [ class "content" ]
[ div
[ class "header"
, Data.Direction.labelFromMaybe item.direction
|> title
]
[ dirIcon
, Util.String.underscoreToSpace item.name
|> text
]
, span [ class "meta" ]
[ div
[ classList
[ ( "ui ribbon label", True )
, ( newColor, True )
, ( "invisible", isConfirmed )
]
]
[ i [ class "exclamation icon" ] []
, text " New"
]
]
, span [ class "right floated meta" ]
[ Util.Time.formatDate item.date |> text
]
]
, div [ class "content" ]
[ div [ class "ui horizontal list" ]
[ div
[ class "item"
, title "Correspondent"
]
[ Icons.correspondentIcon
, text " "
, Util.String.withDefault "-" corr |> text
]
, div
[ class "item"
, title "Concerning"
]
[ Icons.concernedIcon
, text " "
, Util.String.withDefault "-" conc |> text
]
]
, div [ class "right floated meta" ]
[ div [ class "ui horizontal list" ]
[ div
[ class "item"
, title "Source"
]
[ text item.source
]
, div
[ class "item"
, title ("Due on " ++ dueDate)
]
[ div
[ classList
[ ( "ui basic grey label", True )
, ( "invisible hidden", item.dueDate == Nothing )
]
]
[ Icons.dueDateIcon
, text (" " ++ dueDate)
]
]
]
]
]
]

View File

@ -31,6 +31,7 @@ import Comp.SentMails
import Comp.YesNoDimmer
import Data.Direction exposing (Direction)
import Data.Flags exposing (Flags)
import Data.Icons as Icons
import DatePicker exposing (DatePicker)
import Dict exposing (Dict)
import Html exposing (..)
@ -1071,7 +1072,7 @@ view inav model =
[ Html.map DeleteItemConfirm (Comp.YesNoDimmer.view model.deleteItemConfirm)
, div
[ classList
[ ( "four wide column", True )
[ ( "sixteen wide mobile six wide tablet five wide computer column", True )
, ( "invisible", not model.menuOpen )
]
]
@ -1083,7 +1084,7 @@ view inav model =
)
, div
[ classList
[ ( "twelve", model.menuOpen )
[ ( "sixteen wide mobile ten wide tablet eleven wide computer column", model.menuOpen )
, ( "sixteen", not model.menuOpen )
, ( "wide column", True )
]
@ -1416,7 +1417,7 @@ renderItemInfo model =
[ class "item"
, title "Due Date"
]
[ i [ class "bell icon" ] []
[ Icons.dueDateIcon
, Maybe.map Util.Time.formatDate model.item.dueDate
|> Maybe.withDefault ""
|> text
@ -1427,7 +1428,7 @@ renderItemInfo model =
[ class "item"
, title "Correspondent"
]
[ i [ class "envelope outline icon" ] []
[ Icons.correspondentIcon
, List.filterMap identity [ model.item.corrOrg, model.item.corrPerson ]
|> List.map .name
|> String.join ", "
@ -1440,7 +1441,7 @@ renderItemInfo model =
[ class "item"
, title "Concerning"
]
[ i [ class "comment outline icon" ] []
[ Icons.concernedIcon
, List.filterMap identity [ model.item.concPerson, model.item.concEquipment ]
|> List.map .name
|> String.join ", "

View File

@ -5,6 +5,7 @@ module Data.Direction exposing
, icon
, iconFromMaybe
, iconFromString
, labelFromMaybe
, toString
)
@ -70,3 +71,10 @@ iconFromMaybe : Maybe String -> String
iconFromMaybe ms =
Maybe.map iconFromString ms
|> Maybe.withDefault unknownIcon
labelFromMaybe : Maybe String -> String
labelFromMaybe ms =
Maybe.andThen fromString ms
|> Maybe.map toString
|> Maybe.withDefault "Direction"

View File

@ -0,0 +1,41 @@
module Data.Icons exposing
( concerned
, concernedIcon
, correspondent
, correspondentIcon
, dueDate
, dueDateIcon
)
import Html exposing (Html, i)
import Html.Attributes exposing (class)
concerned : String
concerned =
"crosshairs icon"
concernedIcon : Html msg
concernedIcon =
i [ class concerned ] []
correspondent : String
correspondent =
"address card outline icon"
correspondentIcon : Html msg
correspondentIcon =
i [ class correspondent ] []
dueDate : String
dueDate =
"bell icon"
dueDateIcon : Html msg
dueDateIcon =
i [ class dueDate ] []

View File

@ -7,25 +7,27 @@ module Page.Home.Data exposing
)
import Api.Model.ItemLightList exposing (ItemLightList)
import Comp.ItemList
import Comp.ItemCardList
import Comp.SearchMenu
import Http
type alias Model =
{ searchMenuModel : Comp.SearchMenu.Model
, itemListModel : Comp.ItemList.Model
, itemListModel : Comp.ItemCardList.Model
, searchInProgress : Bool
, viewMode : ViewMode
, menuCollapsed : Bool
}
emptyModel : Model
emptyModel =
{ searchMenuModel = Comp.SearchMenu.emptyModel
, itemListModel = Comp.ItemList.emptyModel
, itemListModel = Comp.ItemCardList.init
, searchInProgress = False
, viewMode = Listing
, menuCollapsed = False
}
@ -33,9 +35,10 @@ type Msg
= Init
| SearchMenuMsg Comp.SearchMenu.Msg
| ResetSearch
| ItemListMsg Comp.ItemList.Msg
| ItemCardListMsg Comp.ItemCardList.Msg
| ItemSearchResp (Result Http.Error ItemLightList)
| DoSearch
| ToggleSearchMenu
type ViewMode
@ -47,10 +50,10 @@ itemNav : String -> Model -> { prev : Maybe String, next : Maybe String }
itemNav id model =
let
prev =
Comp.ItemList.prevItem model.itemListModel id
Comp.ItemCardList.prevItem model.itemListModel id
next =
Comp.ItemList.nextItem model.itemListModel id
Comp.ItemCardList.nextItem model.itemListModel id
in
{ prev = Maybe.map .id prev
, next = Maybe.map .id next

View File

@ -2,7 +2,7 @@ module Page.Home.Update exposing (update)
import Api
import Browser.Navigation as Nav
import Comp.ItemList
import Comp.ItemCardList
import Comp.SearchMenu
import Data.Flags exposing (Flags)
import Page exposing (Page(..))
@ -40,10 +40,10 @@ update key flags msg model =
in
( m2, Cmd.batch [ c2, Cmd.map SearchMenuMsg (Tuple.second nextState.modelCmd) ] )
ItemListMsg m ->
ItemCardListMsg m ->
let
( m2, c2, mitem ) =
Comp.ItemList.update flags m model.itemListModel
Comp.ItemCardList.update flags m model.itemListModel
cmd =
case mitem of
@ -53,14 +53,14 @@ update key flags msg model =
Nothing ->
Cmd.none
in
( { model | itemListModel = m2 }, Cmd.batch [ Cmd.map ItemListMsg c2, cmd ] )
( { model | itemListModel = m2 }, Cmd.batch [ Cmd.map ItemCardListMsg c2, cmd ] )
ItemSearchResp (Ok list) ->
let
m =
{ model | searchInProgress = False, viewMode = Listing }
in
update key flags (ItemListMsg (Comp.ItemList.SetResults list)) m
update key flags (ItemCardListMsg (Comp.ItemCardList.SetResults list)) m
ItemSearchResp (Err _) ->
( { model | searchInProgress = False }, Cmd.none )
@ -68,6 +68,11 @@ update key flags msg model =
DoSearch ->
doSearch flags model
ToggleSearchMenu ->
( { model | menuCollapsed = not model.menuCollapsed }
, Cmd.none
)
doSearch : Flags -> Model -> ( Model, Cmd Msg )
doSearch flags model =

View File

@ -1,6 +1,6 @@
module Page.Home.View exposing (view)
import Comp.ItemList
import Comp.ItemCardList
import Comp.SearchMenu
import Html exposing (..)
import Html.Attributes exposing (..)
@ -12,22 +12,39 @@ import Page.Home.Data exposing (..)
view : Model -> Html Msg
view model =
div [ class "home-page ui padded grid" ]
[ div [ class "four wide column" ]
[ div [ class "ui top attached ablue-comp menu" ]
[ h4 [ class "header item" ]
[ text "Search"
[ div
[ classList
[ ( "sixteen wide mobile six wide tablet four wide computer column"
, True
)
, ( "invisible hidden", model.menuCollapsed )
]
]
[ div
[ class "ui top attached ablue-comp menu"
]
[ a
[ class "item"
, href "#"
, onClick ToggleSearchMenu
, title "Hide menu"
]
[ i [ class "ui angle down icon" ] []
, text "Search"
]
, div [ class "right floated menu" ]
[ a
[ class "item"
[ class "icon item"
, onClick ResetSearch
, title "Reset form"
, href "#"
]
[ i [ class "undo icon" ] []
]
, a
[ class "item"
[ class "icon item"
, onClick DoSearch
, title "Run search query"
, href ""
]
[ i [ class "ui search icon" ] []
@ -38,14 +55,37 @@ view model =
[ Html.map SearchMenuMsg (Comp.SearchMenu.view model.searchMenuModel)
]
]
, div [ class "twelve wide column" ]
[ case model.viewMode of
, div
[ classList
[ ( "sixteen wide mobile ten wide tablet twelve wide computer column"
, not model.menuCollapsed
)
, ( "sixteen wide column", model.menuCollapsed )
]
]
[ div
[ classList
[ ( "invisible hidden", not model.menuCollapsed )
, ( "ui segment container", True )
]
]
[ a
[ class "ui basic large circular label"
, onClick ToggleSearchMenu
, href "#"
]
[ i [ class "search icon" ] []
, text "Search Menu"
]
]
, case model.viewMode of
Listing ->
if model.searchInProgress then
resultPlaceholder
else
Html.map ItemListMsg (Comp.ItemList.view model.itemListModel)
Html.map ItemCardListMsg
(Comp.ItemCardList.view model.itemListModel)
Detail ->
div [] []

View File

@ -1,6 +1,7 @@
module Util.String exposing
( crazyEncode
, ellipsis
, underscoreToSpace
, withDefault
)
@ -40,3 +41,8 @@ withDefault default str =
else
str
underscoreToSpace : String -> String
underscoreToSpace str =
String.replace "_" " " str

View File

@ -132,6 +132,14 @@ textarea.markdown-editor {
padding-right: 1em;
}
.default-layout .item-group:not(:first-child) > .ui.horizontal.divider.header.item-list {
margin-top: 1.5em;
}
.default-layout .ui.horizontal.divider.header.item-list {
margin-bottom: 1em;
background: rgba(240,248,255,0.4);
}
label span.muted {
font-size: smaller;
color: rgba(0,0,0,0.6);