mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-12-25 14:42:37 +03:00
Upgraded table versions to allow for additional cell styles
This commit is contained in:
parent
4de053fcd1
commit
ae5e33f919
2
elm.json
2
elm.json
@ -67,8 +67,10 @@
|
|||||||
"Nri.Ui.SlideModal.V1",
|
"Nri.Ui.SlideModal.V1",
|
||||||
"Nri.Ui.SlideModal.V2",
|
"Nri.Ui.SlideModal.V2",
|
||||||
"Nri.Ui.SortableTable.V1",
|
"Nri.Ui.SortableTable.V1",
|
||||||
|
"Nri.Ui.SortableTable.V2",
|
||||||
"Nri.Ui.Table.V3",
|
"Nri.Ui.Table.V3",
|
||||||
"Nri.Ui.Table.V4",
|
"Nri.Ui.Table.V4",
|
||||||
|
"Nri.Ui.Table.V5",
|
||||||
"Nri.Ui.Tabs.V3",
|
"Nri.Ui.Tabs.V3",
|
||||||
"Nri.Ui.Tabs.V4",
|
"Nri.Ui.Tabs.V4",
|
||||||
"Nri.Ui.Text.V2",
|
"Nri.Ui.Text.V2",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
module Nri.Ui.SortableTable.V1 exposing
|
module Nri.Ui.SortableTable.V2 exposing
|
||||||
( Column, Config, Sorter, State
|
( Column, Config, Sorter, State
|
||||||
, init, initDescending
|
, init, initDescending
|
||||||
, custom, string, view, viewLoading
|
, custom, string, view, viewLoading
|
||||||
@ -23,7 +23,7 @@ import Html.Styled.Events
|
|||||||
import Nri.Ui.Colors.Extra
|
import Nri.Ui.Colors.Extra
|
||||||
import Nri.Ui.Colors.V1
|
import Nri.Ui.Colors.V1
|
||||||
import Nri.Ui.CssVendorPrefix.V1 as CssVendorPrefix
|
import Nri.Ui.CssVendorPrefix.V1 as CssVendorPrefix
|
||||||
import Nri.Ui.Table.V4
|
import Nri.Ui.Table.V5
|
||||||
import Svg.Styled as Svg exposing (Svg)
|
import Svg.Styled as Svg exposing (Svg)
|
||||||
import Svg.Styled.Attributes as SvgAttributes
|
import Svg.Styled.Attributes as SvgAttributes
|
||||||
|
|
||||||
@ -46,6 +46,7 @@ type Column id entry msg
|
|||||||
, view : entry -> Html msg
|
, view : entry -> Html msg
|
||||||
, sorter : Sorter entry
|
, sorter : Sorter entry
|
||||||
, width : Int
|
, width : Int
|
||||||
|
, cellStyles : entry -> List Style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -85,15 +86,17 @@ string :
|
|||||||
, header : String
|
, header : String
|
||||||
, value : entry -> String
|
, value : entry -> String
|
||||||
, width : Int
|
, width : Int
|
||||||
|
, cellStyles : entry -> List Style
|
||||||
}
|
}
|
||||||
-> Column id entry msg
|
-> Column id entry msg
|
||||||
string { id, header, value, width } =
|
string { id, header, value, width, cellStyles } =
|
||||||
Column
|
Column
|
||||||
{ id = id
|
{ id = id
|
||||||
, header = Html.text header
|
, header = Html.text header
|
||||||
, view = value >> Html.text
|
, view = value >> Html.text
|
||||||
, sorter = simpleSort value
|
, sorter = simpleSort value
|
||||||
, width = width
|
, width = width
|
||||||
|
, cellStyles = cellStyles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -104,6 +107,7 @@ custom :
|
|||||||
, view : entry -> Html msg
|
, view : entry -> Html msg
|
||||||
, sorter : Sorter entry
|
, sorter : Sorter entry
|
||||||
, width : Int
|
, width : Int
|
||||||
|
, cellStyles : entry -> List Style
|
||||||
}
|
}
|
||||||
-> Column id entry msg
|
-> Column id entry msg
|
||||||
custom config =
|
custom config =
|
||||||
@ -113,6 +117,7 @@ custom config =
|
|||||||
, view = config.view
|
, view = config.view
|
||||||
, sorter = config.sorter
|
, sorter = config.sorter
|
||||||
, width = config.width
|
, width = config.width
|
||||||
|
, cellStyles = config.cellStyles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -181,7 +186,7 @@ viewLoading config state =
|
|||||||
tableColumns =
|
tableColumns =
|
||||||
List.map (buildTableColumn config.updateMsg state) config.columns
|
List.map (buildTableColumn config.updateMsg state) config.columns
|
||||||
in
|
in
|
||||||
Nri.Ui.Table.V4.viewLoading
|
Nri.Ui.Table.V5.viewLoading
|
||||||
tableColumns
|
tableColumns
|
||||||
|
|
||||||
|
|
||||||
@ -195,7 +200,7 @@ view config state entries =
|
|||||||
sorter =
|
sorter =
|
||||||
findSorter config.columns state.column
|
findSorter config.columns state.column
|
||||||
in
|
in
|
||||||
Nri.Ui.Table.V4.view
|
Nri.Ui.Table.V5.view
|
||||||
tableColumns
|
tableColumns
|
||||||
(List.sortWith (sorter state.sortDirection) entries)
|
(List.sortWith (sorter state.sortDirection) entries)
|
||||||
|
|
||||||
@ -230,12 +235,13 @@ identitySorter =
|
|||||||
EQ
|
EQ
|
||||||
|
|
||||||
|
|
||||||
buildTableColumn : (State id -> msg) -> State id -> Column id entry msg -> Nri.Ui.Table.V4.Column entry msg
|
buildTableColumn : (State id -> msg) -> State id -> Column id entry msg -> Nri.Ui.Table.V5.Column entry msg
|
||||||
buildTableColumn updateMsg state (Column column) =
|
buildTableColumn updateMsg state (Column column) =
|
||||||
Nri.Ui.Table.V4.custom
|
Nri.Ui.Table.V5.custom
|
||||||
{ header = viewSortHeader column.header updateMsg state column.id
|
{ header = viewSortHeader column.header updateMsg state column.id
|
||||||
, view = column.view
|
, view = column.view
|
||||||
, width = Css.px (toFloat column.width)
|
, width = Css.px (toFloat column.width)
|
||||||
|
, cellStyles = column.cellStyles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
368
src/Nri/Ui/SortableTable/V2.elm
Normal file
368
src/Nri/Ui/SortableTable/V2.elm
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
module Nri.Ui.SortableTable.V2 exposing
|
||||||
|
( Column, Config, Sorter, State
|
||||||
|
, init, initDescending
|
||||||
|
, custom, string, view, viewLoading
|
||||||
|
, invariantSort, simpleSort, combineSorters
|
||||||
|
)
|
||||||
|
|
||||||
|
{-|
|
||||||
|
|
||||||
|
@docs Column, Config, Sorter, State
|
||||||
|
@docs init, initDescending
|
||||||
|
@docs custom, string, view, viewLoading
|
||||||
|
@docs invariantSort, simpleSort, combineSorters
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Color
|
||||||
|
import Css exposing (..)
|
||||||
|
import Css.Global exposing (Snippet, adjacentSiblings, children, class, descendants, each, everything, media, selector, withClass)
|
||||||
|
import Html.Styled as Html exposing (Html)
|
||||||
|
import Html.Styled.Attributes exposing (css)
|
||||||
|
import Html.Styled.Events
|
||||||
|
import Nri.Ui.Colors.Extra
|
||||||
|
import Nri.Ui.Colors.V1
|
||||||
|
import Nri.Ui.CssVendorPrefix.V1 as CssVendorPrefix
|
||||||
|
import Nri.Ui.Table.V5
|
||||||
|
import Svg.Styled as Svg exposing (Svg)
|
||||||
|
import Svg.Styled.Attributes as SvgAttributes
|
||||||
|
|
||||||
|
|
||||||
|
type SortDirection
|
||||||
|
= Ascending
|
||||||
|
| Descending
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
type alias Sorter a =
|
||||||
|
SortDirection -> a -> a -> Order
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
type Column id entry msg
|
||||||
|
= Column
|
||||||
|
{ id : id
|
||||||
|
, header : Html msg
|
||||||
|
, view : entry -> Html msg
|
||||||
|
, sorter : Sorter entry
|
||||||
|
, width : Int
|
||||||
|
, cellStyles : entry -> List Style
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
type alias State id =
|
||||||
|
{ column : id
|
||||||
|
, sortDirection : SortDirection
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
type alias Config id entry msg =
|
||||||
|
{ updateMsg : State id -> msg
|
||||||
|
, columns : List (Column id entry msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
init : id -> State id
|
||||||
|
init initialSort =
|
||||||
|
{ column = initialSort
|
||||||
|
, sortDirection = Ascending
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
initDescending : id -> State id
|
||||||
|
initDescending initialSort =
|
||||||
|
{ column = initialSort
|
||||||
|
, sortDirection = Descending
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
string :
|
||||||
|
{ id : id
|
||||||
|
, header : String
|
||||||
|
, value : entry -> String
|
||||||
|
, width : Int
|
||||||
|
, cellStyles : entry -> List Style
|
||||||
|
}
|
||||||
|
-> Column id entry msg
|
||||||
|
string { id, header, value, width, cellStyles } =
|
||||||
|
Column
|
||||||
|
{ id = id
|
||||||
|
, header = Html.text header
|
||||||
|
, view = value >> Html.text
|
||||||
|
, sorter = simpleSort value
|
||||||
|
, width = width
|
||||||
|
, cellStyles = cellStyles
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
custom :
|
||||||
|
{ id : id
|
||||||
|
, header : Html msg
|
||||||
|
, view : entry -> Html msg
|
||||||
|
, sorter : Sorter entry
|
||||||
|
, width : Int
|
||||||
|
, cellStyles : entry -> List Style
|
||||||
|
}
|
||||||
|
-> Column id entry msg
|
||||||
|
custom config =
|
||||||
|
Column
|
||||||
|
{ id = config.id
|
||||||
|
, header = config.header
|
||||||
|
, view = config.view
|
||||||
|
, sorter = config.sorter
|
||||||
|
, width = config.width
|
||||||
|
, cellStyles = config.cellStyles
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Create a sorter function that always orders the entries in the same order.
|
||||||
|
For example, this is useful when we want to resolve ties and sort the tied
|
||||||
|
entries by name, no matter of the sort direction set on the table.
|
||||||
|
-}
|
||||||
|
invariantSort : (entry -> comparable) -> Sorter entry
|
||||||
|
invariantSort mapper =
|
||||||
|
\sortDirection elem1 elem2 ->
|
||||||
|
compare (mapper elem1) (mapper elem2)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Create a simple sorter function that orders entries by mapping a function
|
||||||
|
over the collection. It will also reverse it when the sort direction is descending.
|
||||||
|
-}
|
||||||
|
simpleSort : (entry -> comparable) -> Sorter entry
|
||||||
|
simpleSort mapper =
|
||||||
|
\sortDirection elem1 elem2 ->
|
||||||
|
let
|
||||||
|
result =
|
||||||
|
compare (mapper elem1) (mapper elem2)
|
||||||
|
in
|
||||||
|
case sortDirection of
|
||||||
|
Ascending ->
|
||||||
|
result
|
||||||
|
|
||||||
|
Descending ->
|
||||||
|
flipOrder result
|
||||||
|
|
||||||
|
|
||||||
|
flipOrder : Order -> Order
|
||||||
|
flipOrder order =
|
||||||
|
case order of
|
||||||
|
LT ->
|
||||||
|
GT
|
||||||
|
|
||||||
|
EQ ->
|
||||||
|
EQ
|
||||||
|
|
||||||
|
GT ->
|
||||||
|
LT
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
combineSorters : List (Sorter entry) -> Sorter entry
|
||||||
|
combineSorters sorters =
|
||||||
|
\sortDirection elem1 elem2 ->
|
||||||
|
let
|
||||||
|
folder =
|
||||||
|
\sorter acc ->
|
||||||
|
case acc of
|
||||||
|
EQ ->
|
||||||
|
sorter sortDirection elem1 elem2
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
acc
|
||||||
|
in
|
||||||
|
List.foldl folder EQ sorters
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
viewLoading : Config id entry msg -> State id -> Html msg
|
||||||
|
viewLoading config state =
|
||||||
|
let
|
||||||
|
tableColumns =
|
||||||
|
List.map (buildTableColumn config.updateMsg state) config.columns
|
||||||
|
in
|
||||||
|
Nri.Ui.Table.V5.viewLoading
|
||||||
|
tableColumns
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
view : Config id entry msg -> State id -> List entry -> Html msg
|
||||||
|
view config state entries =
|
||||||
|
let
|
||||||
|
tableColumns =
|
||||||
|
List.map (buildTableColumn config.updateMsg state) config.columns
|
||||||
|
|
||||||
|
sorter =
|
||||||
|
findSorter config.columns state.column
|
||||||
|
in
|
||||||
|
Nri.Ui.Table.V5.view
|
||||||
|
tableColumns
|
||||||
|
(List.sortWith (sorter state.sortDirection) entries)
|
||||||
|
|
||||||
|
|
||||||
|
findSorter : List (Column id entry msg) -> id -> Sorter entry
|
||||||
|
findSorter columns columnId =
|
||||||
|
columns
|
||||||
|
|> listExtraFind (\(Column column) -> column.id == columnId)
|
||||||
|
|> Maybe.map (\(Column column) -> column.sorter)
|
||||||
|
|> Maybe.withDefault identitySorter
|
||||||
|
|
||||||
|
|
||||||
|
{-| Taken from <https://github.com/elm-community/list-extra/blob/8.2.0/src/List/Extra.elm#L556>
|
||||||
|
-}
|
||||||
|
listExtraFind : (a -> Bool) -> List a -> Maybe a
|
||||||
|
listExtraFind predicate list =
|
||||||
|
case list of
|
||||||
|
[] ->
|
||||||
|
Nothing
|
||||||
|
|
||||||
|
first :: rest ->
|
||||||
|
if predicate first then
|
||||||
|
Just first
|
||||||
|
|
||||||
|
else
|
||||||
|
listExtraFind predicate rest
|
||||||
|
|
||||||
|
|
||||||
|
identitySorter : Sorter a
|
||||||
|
identitySorter =
|
||||||
|
\sortDirection item1 item2 ->
|
||||||
|
EQ
|
||||||
|
|
||||||
|
|
||||||
|
buildTableColumn : (State id -> msg) -> State id -> Column id entry msg -> Nri.Ui.Table.V5.Column entry msg
|
||||||
|
buildTableColumn updateMsg state (Column column) =
|
||||||
|
Nri.Ui.Table.V5.custom
|
||||||
|
{ header = viewSortHeader column.header updateMsg state column.id
|
||||||
|
, view = column.view
|
||||||
|
, width = Css.px (toFloat column.width)
|
||||||
|
, cellStyles = column.cellStyles
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
viewSortHeader : Html msg -> (State id -> msg) -> State id -> id -> Html msg
|
||||||
|
viewSortHeader header updateMsg state id =
|
||||||
|
let
|
||||||
|
nextState =
|
||||||
|
nextTableState state id
|
||||||
|
in
|
||||||
|
Html.div
|
||||||
|
[ css
|
||||||
|
[ Css.displayFlex
|
||||||
|
, Css.alignItems Css.center
|
||||||
|
, Css.justifyContent Css.spaceBetween
|
||||||
|
, cursor pointer
|
||||||
|
, CssVendorPrefix.property "user-select" "none"
|
||||||
|
, if state.column == id then
|
||||||
|
fontWeight bold
|
||||||
|
|
||||||
|
else
|
||||||
|
fontWeight normal
|
||||||
|
]
|
||||||
|
, Html.Styled.Events.onClick (updateMsg nextState)
|
||||||
|
]
|
||||||
|
[ Html.div [] [ header ]
|
||||||
|
, viewSortButton updateMsg state id
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewSortButton : (State id -> msg) -> State id -> id -> Html msg
|
||||||
|
viewSortButton updateMsg state id =
|
||||||
|
let
|
||||||
|
arrows upHighlighted downHighlighted =
|
||||||
|
Html.div
|
||||||
|
[ css
|
||||||
|
[ Css.displayFlex
|
||||||
|
, Css.flexDirection Css.column
|
||||||
|
, Css.alignItems Css.center
|
||||||
|
, Css.justifyContent Css.center
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ sortArrow Up upHighlighted
|
||||||
|
, sortArrow Down downHighlighted
|
||||||
|
]
|
||||||
|
|
||||||
|
buttonContent =
|
||||||
|
case ( state.column == id, state.sortDirection ) of
|
||||||
|
( True, Ascending ) ->
|
||||||
|
arrows True False
|
||||||
|
|
||||||
|
( True, Descending ) ->
|
||||||
|
arrows False True
|
||||||
|
|
||||||
|
( False, _ ) ->
|
||||||
|
arrows False False
|
||||||
|
in
|
||||||
|
Html.div [ css [ padding (px 2) ] ] [ buttonContent ]
|
||||||
|
|
||||||
|
|
||||||
|
nextTableState : State id -> id -> State id
|
||||||
|
nextTableState state id =
|
||||||
|
if state.column == id then
|
||||||
|
{ column = id
|
||||||
|
, sortDirection = flipSortDirection state.sortDirection
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{ column = id
|
||||||
|
, sortDirection = Ascending
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
flipSortDirection : SortDirection -> SortDirection
|
||||||
|
flipSortDirection order =
|
||||||
|
case order of
|
||||||
|
Ascending ->
|
||||||
|
Descending
|
||||||
|
|
||||||
|
Descending ->
|
||||||
|
Ascending
|
||||||
|
|
||||||
|
|
||||||
|
type Direction
|
||||||
|
= Up
|
||||||
|
| Down
|
||||||
|
|
||||||
|
|
||||||
|
sortArrow : Direction -> Bool -> Html msg
|
||||||
|
sortArrow direction active =
|
||||||
|
Html.div
|
||||||
|
[ css
|
||||||
|
[ width (px 8)
|
||||||
|
, height (px 6)
|
||||||
|
, position relative
|
||||||
|
, margin2 (px 1) zero
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[ Svg.svg
|
||||||
|
[ SvgAttributes.viewBox "0 0 8 6"
|
||||||
|
, SvgAttributes.css
|
||||||
|
[ position absolute
|
||||||
|
, top zero
|
||||||
|
, left zero
|
||||||
|
, case direction of
|
||||||
|
Up ->
|
||||||
|
Css.batch []
|
||||||
|
|
||||||
|
Down ->
|
||||||
|
Css.batch [ transform <| rotate (deg 180) ]
|
||||||
|
]
|
||||||
|
, if active then
|
||||||
|
SvgAttributes.fill (toCssString Nri.Ui.Colors.V1.azure)
|
||||||
|
|
||||||
|
else
|
||||||
|
SvgAttributes.fill (toCssString Nri.Ui.Colors.V1.gray75)
|
||||||
|
]
|
||||||
|
[ Svg.polygon [ SvgAttributes.points "0 6 4 0 8 6 0 6" ] []
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
toCssString : Css.Color -> String
|
||||||
|
toCssString =
|
||||||
|
Color.toCssString << Nri.Ui.Colors.Extra.toCoreColor
|
@ -1,4 +1,4 @@
|
|||||||
module Nri.Ui.Table.V4 exposing
|
module Nri.Ui.Table.V5 exposing
|
||||||
( Column, custom, string
|
( Column, custom, string
|
||||||
, view, viewWithoutHeader
|
, view, viewWithoutHeader
|
||||||
, viewLoading, viewLoadingWithoutHeader
|
, viewLoading, viewLoadingWithoutHeader
|
||||||
@ -39,7 +39,7 @@ import Nri.Ui.Fonts.V1 exposing (baseFont)
|
|||||||
in the table
|
in the table
|
||||||
-}
|
-}
|
||||||
type Column data msg
|
type Column data msg
|
||||||
= Column (Html msg) (data -> Html msg) Style
|
= Column (Html msg) (data -> Html msg) Style (data -> List Style)
|
||||||
|
|
||||||
|
|
||||||
{-| A column that renders some aspect of a value as text
|
{-| A column that renders some aspect of a value as text
|
||||||
@ -48,10 +48,11 @@ string :
|
|||||||
{ header : String
|
{ header : String
|
||||||
, value : data -> String
|
, value : data -> String
|
||||||
, width : LengthOrAuto compatible
|
, width : LengthOrAuto compatible
|
||||||
|
, cellStyles : data -> List Style
|
||||||
}
|
}
|
||||||
-> Column data msg
|
-> Column data msg
|
||||||
string { header, value, width } =
|
string { header, value, width, cellStyles } =
|
||||||
Column (Html.text header) (value >> Html.text) (Css.width width)
|
Column (Html.text header) (value >> Html.text) (Css.width width) cellStyles
|
||||||
|
|
||||||
|
|
||||||
{-| A column that renders however you want it to
|
{-| A column that renders however you want it to
|
||||||
@ -60,10 +61,11 @@ custom :
|
|||||||
{ header : Html msg
|
{ header : Html msg
|
||||||
, view : data -> Html msg
|
, view : data -> Html msg
|
||||||
, width : LengthOrAuto compatible
|
, width : LengthOrAuto compatible
|
||||||
|
, cellStyles : data -> List Style
|
||||||
}
|
}
|
||||||
-> Column data msg
|
-> Column data msg
|
||||||
custom options =
|
custom options =
|
||||||
Column options.header options.view (Css.width options.width)
|
Column options.header options.view (Css.width options.width) options.cellStyles
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -92,9 +94,9 @@ viewRow columns data =
|
|||||||
|
|
||||||
|
|
||||||
viewColumn : data -> Column data msg -> Html msg
|
viewColumn : data -> Column data msg -> Html msg
|
||||||
viewColumn data (Column _ renderer width) =
|
viewColumn data (Column _ renderer width cellStyles) =
|
||||||
td
|
td
|
||||||
[ css (width :: cellStyles)
|
[ css ([ width, verticalAlign middle ] ++ cellStyles data)
|
||||||
]
|
]
|
||||||
[ renderer data ]
|
[ renderer data ]
|
||||||
|
|
||||||
@ -127,9 +129,9 @@ viewLoadingRow columns index =
|
|||||||
|
|
||||||
|
|
||||||
viewLoadingColumn : Int -> Int -> Column data msg -> Html msg
|
viewLoadingColumn : Int -> Int -> Column data msg -> Html msg
|
||||||
viewLoadingColumn rowIndex colIndex (Column _ _ width) =
|
viewLoadingColumn rowIndex colIndex (Column _ _ width _) =
|
||||||
td
|
td
|
||||||
[ css (stylesLoadingColumn rowIndex colIndex width ++ cellStyles ++ loadingCellStyles)
|
[ css (stylesLoadingColumn rowIndex colIndex width ++ [ verticalAlign middle ] ++ loadingCellStyles)
|
||||||
]
|
]
|
||||||
[ span [ css loadingContentStyles ] [] ]
|
[ span [ css loadingContentStyles ] [] ]
|
||||||
|
|
||||||
@ -174,7 +176,7 @@ tableHeader columns =
|
|||||||
|
|
||||||
|
|
||||||
tableRowHeader : Column data msg -> Html msg
|
tableRowHeader : Column data msg -> Html msg
|
||||||
tableRowHeader (Column header _ width) =
|
tableRowHeader (Column header _ width _) =
|
||||||
th
|
th
|
||||||
[ css (width :: headerStyles)
|
[ css (width :: headerStyles)
|
||||||
]
|
]
|
||||||
@ -216,12 +218,6 @@ rowStyles =
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
cellStyles : List Style
|
|
||||||
cellStyles =
|
|
||||||
[ verticalAlign middle
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
loadingContentStyles : List Style
|
loadingContentStyles : List Style
|
||||||
loadingContentStyles =
|
loadingContentStyles =
|
||||||
[ width (pct 100)
|
[ width (pct 100)
|
||||||
|
285
src/Nri/Ui/Table/V5.elm
Normal file
285
src/Nri/Ui/Table/V5.elm
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
module Nri.Ui.Table.V5 exposing
|
||||||
|
( Column, custom, string
|
||||||
|
, view, viewWithoutHeader
|
||||||
|
, viewLoading, viewLoadingWithoutHeader
|
||||||
|
)
|
||||||
|
|
||||||
|
{-| Upgrading from V1:
|
||||||
|
|
||||||
|
- All the `width` fields in column configurations now take an elm-css length
|
||||||
|
value rather than an Integer. Change `width = 100` to `width = px 100` to get
|
||||||
|
the same widths as before.
|
||||||
|
- Tables now by default take the full width of the container they are placed in.
|
||||||
|
If this is not what you want, wrap the table in an element with a fixed width.
|
||||||
|
- The table module now makes use of `Html.Styled` and no longer exposes a
|
||||||
|
separate `styles` value.
|
||||||
|
Check out the [elm-css](http://package.elm-lang.org/packages/rtfeldman/elm-css/14.0.0/Html-Styled)
|
||||||
|
documentation on Html.Styled to see how to work with it.
|
||||||
|
- The default cell padding has been removed and content is not vertically
|
||||||
|
centered in its cell. If you need to overwrite this, wrap your cells in
|
||||||
|
elements providing custom styling to the cell.
|
||||||
|
|
||||||
|
@docs Column, custom, string
|
||||||
|
|
||||||
|
@docs view, viewWithoutHeader
|
||||||
|
|
||||||
|
@docs viewLoading, viewLoadingWithoutHeader
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Css exposing (..)
|
||||||
|
import Css.Animations
|
||||||
|
import Html.Styled as Html exposing (..)
|
||||||
|
import Html.Styled.Attributes exposing (css)
|
||||||
|
import Nri.Ui.Colors.V1 exposing (..)
|
||||||
|
import Nri.Ui.Fonts.V1 exposing (baseFont)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Closed representation of how to render the header and cells of a column
|
||||||
|
in the table
|
||||||
|
-}
|
||||||
|
type Column data msg
|
||||||
|
= Column (Html msg) (data -> Html msg) Style (data -> List Style)
|
||||||
|
|
||||||
|
|
||||||
|
{-| A column that renders some aspect of a value as text
|
||||||
|
-}
|
||||||
|
string :
|
||||||
|
{ header : String
|
||||||
|
, value : data -> String
|
||||||
|
, width : LengthOrAuto compatible
|
||||||
|
, cellStyles : data -> List Style
|
||||||
|
}
|
||||||
|
-> Column data msg
|
||||||
|
string { header, value, width, cellStyles } =
|
||||||
|
Column (Html.text header) (value >> Html.text) (Css.width width) cellStyles
|
||||||
|
|
||||||
|
|
||||||
|
{-| A column that renders however you want it to
|
||||||
|
-}
|
||||||
|
custom :
|
||||||
|
{ header : Html msg
|
||||||
|
, view : data -> Html msg
|
||||||
|
, width : LengthOrAuto compatible
|
||||||
|
, cellStyles : data -> List Style
|
||||||
|
}
|
||||||
|
-> Column data msg
|
||||||
|
custom options =
|
||||||
|
Column options.header options.view (Css.width options.width) options.cellStyles
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- VIEW
|
||||||
|
|
||||||
|
|
||||||
|
{-| Displays a table of data without a header row
|
||||||
|
-}
|
||||||
|
viewWithoutHeader : List (Column data msg) -> List data -> Html msg
|
||||||
|
viewWithoutHeader columns =
|
||||||
|
tableWithoutHeader [] columns (viewRow columns)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Displays a table of data based on the provided column definitions
|
||||||
|
-}
|
||||||
|
view : List (Column data msg) -> List data -> Html msg
|
||||||
|
view columns =
|
||||||
|
tableWithHeader [] columns (viewRow columns)
|
||||||
|
|
||||||
|
|
||||||
|
viewRow : List (Column data msg) -> data -> Html msg
|
||||||
|
viewRow columns data =
|
||||||
|
tr
|
||||||
|
[ css rowStyles ]
|
||||||
|
(List.map (viewColumn data) columns)
|
||||||
|
|
||||||
|
|
||||||
|
viewColumn : data -> Column data msg -> Html msg
|
||||||
|
viewColumn data (Column _ renderer width cellStyles) =
|
||||||
|
td
|
||||||
|
[ css ([ width, verticalAlign middle ] ++ cellStyles data)
|
||||||
|
]
|
||||||
|
[ renderer data ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- VIEW LOADING
|
||||||
|
|
||||||
|
|
||||||
|
{-| Display a table with the given columns but instead of data, show blocked
|
||||||
|
out text with an interesting animation. This view lets the user know that
|
||||||
|
data is on its way and what it will look like when it arrives.
|
||||||
|
-}
|
||||||
|
viewLoading : List (Column data msg) -> Html msg
|
||||||
|
viewLoading columns =
|
||||||
|
tableWithHeader loadingTableStyles columns (viewLoadingRow columns) (List.range 0 8)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Display the loading table without a header row
|
||||||
|
-}
|
||||||
|
viewLoadingWithoutHeader : List (Column data msg) -> Html msg
|
||||||
|
viewLoadingWithoutHeader columns =
|
||||||
|
tableWithoutHeader loadingTableStyles columns (viewLoadingRow columns) (List.range 0 8)
|
||||||
|
|
||||||
|
|
||||||
|
viewLoadingRow : List (Column data msg) -> Int -> Html msg
|
||||||
|
viewLoadingRow columns index =
|
||||||
|
tr
|
||||||
|
[ css rowStyles ]
|
||||||
|
(List.indexedMap (viewLoadingColumn index) columns)
|
||||||
|
|
||||||
|
|
||||||
|
viewLoadingColumn : Int -> Int -> Column data msg -> Html msg
|
||||||
|
viewLoadingColumn rowIndex colIndex (Column _ _ width _) =
|
||||||
|
td
|
||||||
|
[ css (stylesLoadingColumn rowIndex colIndex width ++ [ verticalAlign middle ] ++ loadingCellStyles)
|
||||||
|
]
|
||||||
|
[ span [ css loadingContentStyles ] [] ]
|
||||||
|
|
||||||
|
|
||||||
|
stylesLoadingColumn : Int -> Int -> Style -> List Style
|
||||||
|
stylesLoadingColumn rowIndex colIndex width =
|
||||||
|
[ width
|
||||||
|
, property "animation-delay" (String.fromFloat (toFloat (rowIndex + colIndex) * 0.1) ++ "s")
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- HELP
|
||||||
|
|
||||||
|
|
||||||
|
tableWithoutHeader : List Style -> List (Column data msg) -> (a -> Html msg) -> List a -> Html msg
|
||||||
|
tableWithoutHeader styles columns toRow data =
|
||||||
|
table styles
|
||||||
|
[ tableBody toRow data
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
tableWithHeader : List Style -> List (Column data msg) -> (a -> Html msg) -> List a -> Html msg
|
||||||
|
tableWithHeader styles columns toRow data =
|
||||||
|
table styles
|
||||||
|
[ tableHeader columns
|
||||||
|
, tableBody toRow data
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
table : List Style -> List (Html msg) -> Html msg
|
||||||
|
table styles =
|
||||||
|
Html.table [ css (styles ++ tableStyles) ]
|
||||||
|
|
||||||
|
|
||||||
|
tableHeader : List (Column data msg) -> Html msg
|
||||||
|
tableHeader columns =
|
||||||
|
thead []
|
||||||
|
[ tr [ css headersStyles ]
|
||||||
|
(List.map tableRowHeader columns)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
tableRowHeader : Column data msg -> Html msg
|
||||||
|
tableRowHeader (Column header _ width _) =
|
||||||
|
th
|
||||||
|
[ css (width :: headerStyles)
|
||||||
|
]
|
||||||
|
[ header ]
|
||||||
|
|
||||||
|
|
||||||
|
tableBody : (a -> Html msg) -> List a -> Html msg
|
||||||
|
tableBody toRow items =
|
||||||
|
tbody [] (List.map toRow items)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- STYLES
|
||||||
|
|
||||||
|
|
||||||
|
headersStyles : List Style
|
||||||
|
headersStyles =
|
||||||
|
[ borderBottom3 (px 3) solid gray75
|
||||||
|
, height (px 45)
|
||||||
|
, fontSize (px 15)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
headerStyles : List Style
|
||||||
|
headerStyles =
|
||||||
|
[ padding4 (px 15) (px 12) (px 11) (px 12)
|
||||||
|
, textAlign left
|
||||||
|
, fontWeight bold
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
rowStyles : List Style
|
||||||
|
rowStyles =
|
||||||
|
[ height (px 45)
|
||||||
|
, fontSize (px 14)
|
||||||
|
, color gray20
|
||||||
|
, pseudoClass "nth-child(odd)"
|
||||||
|
[ backgroundColor gray96 ]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
loadingContentStyles : List Style
|
||||||
|
loadingContentStyles =
|
||||||
|
[ width (pct 100)
|
||||||
|
, display inlineBlock
|
||||||
|
, height (Css.em 1)
|
||||||
|
, borderRadius (Css.em 1)
|
||||||
|
, backgroundColor gray75
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
loadingCellStyles : List Style
|
||||||
|
loadingCellStyles =
|
||||||
|
[ batch flashAnimation
|
||||||
|
, padding2 (px 14) (px 10)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
loadingTableStyles : List Style
|
||||||
|
loadingTableStyles =
|
||||||
|
fadeInAnimation
|
||||||
|
|
||||||
|
|
||||||
|
tableStyles : List Style
|
||||||
|
tableStyles =
|
||||||
|
[ borderCollapse collapse
|
||||||
|
, baseFont
|
||||||
|
, Css.width (Css.pct 100)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
flash : Css.Animations.Keyframes {}
|
||||||
|
flash =
|
||||||
|
Css.Animations.keyframes
|
||||||
|
[ ( 0, [ Css.Animations.opacity (Css.num 0.6) ] )
|
||||||
|
, ( 50, [ Css.Animations.opacity (Css.num 0.2) ] )
|
||||||
|
, ( 100, [ Css.Animations.opacity (Css.num 0.6) ] )
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
fadeIn : Css.Animations.Keyframes {}
|
||||||
|
fadeIn =
|
||||||
|
Css.Animations.keyframes
|
||||||
|
[ ( 0, [ Css.Animations.opacity (Css.num 0) ] )
|
||||||
|
, ( 100, [ Css.Animations.opacity (Css.num 1) ] )
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
flashAnimation : List Css.Style
|
||||||
|
flashAnimation =
|
||||||
|
[ animationName flash
|
||||||
|
, property "animation-duration" "2s"
|
||||||
|
, property "animation-iteration-count" "infinite"
|
||||||
|
, opacity (num 0.6)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
fadeInAnimation : List Css.Style
|
||||||
|
fadeInAnimation =
|
||||||
|
[ animationName fadeIn
|
||||||
|
, property "animation-duration" "0.4s"
|
||||||
|
, property "animation-delay" "0.2s"
|
||||||
|
, property "animation-fill-mode" "forwards"
|
||||||
|
, animationIterationCount (int 1)
|
||||||
|
, opacity (num 0)
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user