1- import { Icon as BpIcon } from '@blueprintjs/core/lib/esm/components/icon/icon' ;
1+ import 'ag-grid-community/styles/ag-grid.css' ;
2+ import 'ag-grid-community/styles/ag-theme-quartz.css' ;
3+
4+ import { Icon } from '@blueprintjs/core' ;
25import { IconNames } from '@blueprintjs/icons' ;
3- import {
4- Flex ,
5- Icon ,
6- Table ,
7- TableBody ,
8- TableCell ,
9- TableHead ,
10- TableHeaderCell ,
11- TableRow ,
12- Text
13- } from '@tremor/react' ;
14- import React from 'react' ;
6+ import { ColDef } from 'ag-grid-community' ;
7+ import { AgGridReact , CustomCellRendererProps } from 'ag-grid-react' ;
8+ import React , { useMemo } from 'react' ;
9+ import GradingFlex from 'src/commons/grading/GradingFlex' ;
1510import { StoryListView } from 'src/features/stories/StoriesTypes' ;
11+ import classes from 'src/styles/Stories.module.scss' ;
1612
1713type Props = {
1814 headers : Array < { id : string ; header : string } > ;
@@ -22,45 +18,63 @@ type Props = {
2218
2319const MAX_EXCERPT_LENGTH = 35 ;
2420
21+ const truncate = ( content : string ) => {
22+ return content . replaceAll ( / \s + / g, ' ' ) . length <= MAX_EXCERPT_LENGTH
23+ ? content . replaceAll ( / \s + / g, ' ' )
24+ : content . split ( / \s + / ) . reduce ( ( acc , cur ) => {
25+ return acc . length + cur . length <= MAX_EXCERPT_LENGTH ? acc + ' ' + cur : acc ;
26+ } , '' ) + '…' ;
27+ } ;
28+
29+ const defaultColDef : ColDef < StoryListView > = {
30+ cellClass : ( { data } ) => ( data ?. isPinned ? classes [ 'highlight-row' ] : '' )
31+ } ;
32+
2533const StoriesTable : React . FC < Props > = ( { headers, stories, storyActions } ) => {
34+ const columns : ColDef < StoryListView > [ ] = useMemo (
35+ ( ) => [
36+ { flex : 2 , field : 'authorName' , headerName : 'Author' } ,
37+ {
38+ flex : 4 ,
39+ field : 'title' ,
40+ headerName : 'Title' ,
41+ cellRenderer : ( { data, value } : CustomCellRendererProps < StoryListView > ) =>
42+ data && (
43+ < GradingFlex alignItems = "center" style = { { columnGap : 8 } } >
44+ { data . isPinned && < Icon intent = "primary" icon = { IconNames . PIN } /> }
45+ { value }
46+ </ GradingFlex >
47+ )
48+ } ,
49+ {
50+ flex : 6 ,
51+ field : 'content' ,
52+ headerName : 'Content' ,
53+ valueFormatter : ( { value } ) => truncate ( value ) ,
54+ cellStyle : { textAlign : 'left' }
55+ } ,
56+ {
57+ flex : 3 ,
58+ field : 'actions' as any ,
59+ headerName : 'Actions' ,
60+ sortable : false ,
61+ cellRenderer : ( { data } : CustomCellRendererProps < StoryListView > ) => storyActions ( data ! )
62+ }
63+ ] ,
64+ [ storyActions ]
65+ ) ;
66+
2667 return (
27- < Table marginTop = "mt-10" >
28- < TableHead >
29- < TableRow >
30- { headers . map ( ( { id, header } ) => (
31- < TableHeaderCell key = { id } > { header } </ TableHeaderCell >
32- ) ) }
33- </ TableRow >
34- </ TableHead >
35- < TableBody >
36- { stories . map ( story => {
37- const { id, authorName, isPinned, title, content } = story ;
38- return (
39- < TableRow key = { id } >
40- < TableCell > { authorName } </ TableCell >
41- < TableCell >
42- < Flex justifyContent = "justify-start" >
43- { isPinned && < Icon icon = { ( ) => < BpIcon icon = { IconNames . PIN } /> } /> }
44- < Text > { title } </ Text >
45- </ Flex >
46- </ TableCell >
47- < TableCell >
48- < Text >
49- { content . replaceAll ( / \s + / g, ' ' ) . length <= MAX_EXCERPT_LENGTH
50- ? content . replaceAll ( / \s + / g, ' ' )
51- : content . split ( / \s + / ) . reduce ( ( acc , cur ) => {
52- return acc . length + cur . length <= MAX_EXCERPT_LENGTH
53- ? acc + ' ' + cur
54- : acc ;
55- } , '' ) + '…' }
56- </ Text >
57- </ TableCell >
58- < TableCell > { storyActions ( story ) } </ TableCell >
59- </ TableRow >
60- ) ;
61- } ) }
62- </ TableBody >
63- </ Table >
68+ < div className = "ag-theme-quartz" style = { { marginTop : 24 } } >
69+ < AgGridReact
70+ rowData = { stories }
71+ columnDefs = { columns }
72+ defaultColDef = { defaultColDef }
73+ domLayout = "autoHeight"
74+ suppressMovableColumns
75+ suppressCellFocus
76+ />
77+ </ div >
6478 ) ;
6579} ;
6680
0 commit comments