1- import { Classes , Colors , HTMLTable } from '@blueprintjs/core'
1+ import { Colors } from '@blueprintjs/core'
22import styled from '@emotion/styled'
33import type { StringItem } from '@/search/interface'
44import { highlightText } from '@/utils/highlight'
55import { languageMap } from '@/utils/language'
66import { useScrollIntoView } from '../utils/useScrollIntoView'
77
8- const HighlightedTbody = styled . tbody ( {
9- em : {
10- textDecoration : 'none' ,
11- backgroundColor : Colors . GOLD5 ,
12- fontStyle : 'normal' ,
8+ const MOBILE_BREAKPOINT = 768
9+
10+ const ListContainer = styled . div ( {
11+ width : '100%' ,
12+ minWidth : 0 ,
13+ display : 'flex' ,
14+ flexDirection : 'column' ,
15+ } )
16+
17+ const HeaderRow = styled . div ( {
18+ display : 'flex' ,
19+ flexDirection : 'row' ,
20+ borderBottom : '2px solid #e1e8ed' ,
21+ backgroundColor : '#f7f9fa' ,
22+ fontWeight : 600 ,
23+ fontSize : 12 ,
24+ color : '#5c7080' ,
25+ [ `@media (max-width: ${ MOBILE_BREAKPOINT - 1 } px)` ] : {
26+ display : 'none' ,
1327 } ,
14- td : {
15- whiteSpace : 'pre-wrap' ,
16- wordBreak : 'break-word' ,
17- cursor : 'auto' ,
28+ } )
29+
30+ const HeaderCellPosition = styled . div ( {
31+ flex : '0 0 120px' ,
32+ minWidth : 0 ,
33+ padding : '10px 12px' ,
34+ borderRight : '1px solid #e1e8ed' ,
35+ } )
36+
37+ const HeaderCellLang = styled . div ( {
38+ flex : 1 ,
39+ minWidth : 0 ,
40+ padding : '10px 12px' ,
41+ borderRight : '1px solid #e1e8ed' ,
42+ '&:last-of-type' : {
43+ borderRight : 'none' ,
44+ } ,
45+ } )
46+
47+ const ItemRow = styled . div < { $highlight ?: boolean } > ( ( { $highlight } ) => ( {
48+ display : 'flex' ,
49+ flexDirection : 'row' ,
50+ minWidth : 0 ,
51+ borderBottom : '1px solid #e1e8ed' ,
52+ '&:hover' : {
53+ backgroundColor : Colors . LIGHT_GRAY4 ,
1854 } ,
19- 'td:nth-of-type(1)' : {
20- fontSize : 12 ,
21- fontFamily : 'monospace' ,
55+ ...( $highlight && {
56+ backgroundColor : '#fef4a8' ,
57+ } ) ,
58+ [ `@media (max-width: ${ MOBILE_BREAKPOINT - 1 } px)` ] : {
59+ flexDirection : 'column' ,
60+ border : '1px solid #e1e8ed' ,
61+ borderRadius : 8 ,
62+ marginBottom : 12 ,
63+ padding : 12 ,
64+ boxShadow : '0 1px 3px rgba(0,0,0,0.08)' ,
65+ '&:hover' : {
66+ backgroundColor : 'transparent' ,
67+ } ,
68+ ...( $highlight && {
69+ backgroundColor : '#fef4a8' ,
70+ borderColor : '#d99e0b' ,
71+ } ) ,
2272 } ,
23- '.highlight-row td' : {
24- backgroundColor : `#fef4a8 !important` ,
73+ } ) )
74+
75+ const CellPosition = styled . div ( {
76+ flex : '0 0 120px' ,
77+ minWidth : 0 ,
78+ padding : '10px 12px' ,
79+ borderRight : '1px solid #e1e8ed' ,
80+ fontSize : 12 ,
81+ fontFamily : 'monospace' ,
82+ whiteSpace : 'pre-wrap' ,
83+ wordBreak : 'break-word' ,
84+ [ `@media (max-width: ${ MOBILE_BREAKPOINT - 1 } px)` ] : {
85+ flex : 'none' ,
86+ width : '100%' ,
87+ borderRight : 'none' ,
88+ borderBottom : '1px solid #e1e8ed' ,
89+ marginBottom : 8 ,
90+ paddingTop : 0 ,
91+ paddingBottom : 8 ,
92+ paddingLeft : 0 ,
93+ paddingRight : 0 ,
2594 } ,
2695} )
2796
28- const StyledHtmlTable = styled ( HTMLTable ) ( {
29- minWidth : 700 ,
30- width : '100%' ,
31- tableLayout : 'fixed' ,
32- [ `&.${ Classes . HTML_TABLE } .${ Classes . HTML_TABLE_STRIPED } tbody tr:hover td` ] : {
33- backgroundColor : Colors . LIGHT_GRAY4 ,
97+ const CellLang = styled . div ( {
98+ flex : 1 ,
99+ minWidth : 0 ,
100+ padding : '10px 12px' ,
101+ borderRight : '1px solid #e1e8ed' ,
102+ whiteSpace : 'pre-wrap' ,
103+ wordBreak : 'break-word' ,
104+ fontSize : 14 ,
105+ '&:last-of-type' : {
106+ borderRight : 'none' ,
34107 } ,
35- borderCollapse : 'collapse' ,
36- 'th, tr, td' : {
37- border : '1px solid #fff' ,
108+ '& em' : {
109+ textDecoration : 'none' ,
110+ backgroundColor : Colors . GOLD5 ,
111+ fontStyle : 'normal' ,
112+ } ,
113+ [ `@media (max-width: ${ MOBILE_BREAKPOINT - 1 } px)` ] : {
114+ display : 'flex' ,
115+ flexDirection : 'row' ,
116+ flex : 'none' ,
117+ width : '100%' ,
118+ borderRight : 'none' ,
119+ paddingLeft : 0 ,
120+ paddingRight : 0 ,
121+ paddingTop : 6 ,
122+ paddingBottom : 0 ,
123+ '&::before' : {
124+ content : 'attr(data-label)' ,
125+ fontWeight : 600 ,
126+ display : 'inline-block' ,
127+ minWidth : 72 ,
128+ marginRight : 8 ,
129+ color : '#5c7080' ,
130+ } ,
38131 } ,
39132} )
40133
41134const ScrollableContainer = styled . div ( {
42135 width : '100%' ,
136+ minWidth : 0 ,
43137 overflowX : 'auto' ,
138+ [ `@media (max-width: ${ MOBILE_BREAKPOINT - 1 } px)` ] : {
139+ overflowX : 'visible' ,
140+ } ,
44141} )
45142
46143const LinkButton = styled . button ( {
@@ -50,6 +147,7 @@ const LinkButton = styled.button({
50147 backgroundColor : 'transparent' ,
51148 color : Colors . BLUE3 ,
52149 cursor : 'pointer' ,
150+ fontSize : 12 ,
53151 '&:hover' : {
54152 textDecoration : 'underline' ,
55153 } ,
@@ -65,60 +163,49 @@ export interface IResultTableProps {
65163
66164export function ResultTable ( props : IResultTableProps ) {
67165 const { items, keyword, displayLanguages } = props
68- useScrollIntoView ( '. highlight-row' , [ props . highlightItem ] )
166+ useScrollIntoView ( '[data- highlight-row="true"] ' , [ props . highlightItem ] )
69167
70168 return (
71169 < ScrollableContainer >
72- < StyledHtmlTable striped >
73- < colgroup >
74- < col style = { { width : '120px' } } />
75- < col
76- span = { displayLanguages . length }
77- style = { {
78- width : `calc((100% - 120px) / ${ displayLanguages . length } )` ,
79- } }
80- />
81- </ colgroup >
82- < thead >
83- < tr >
84- < th > 位置</ th >
85- { displayLanguages . map ( ( lang ) => (
86- < th key = { lang } >
87- { languageMap [ lang as keyof typeof languageMap ] }
88- </ th >
89- ) ) }
90- </ tr >
91- </ thead >
92- < HighlightedTbody className = { Classes . TEXT_LARGE } >
93- { items . map ( ( item , idx ) => (
94- < tr
170+ < ListContainer >
171+ < HeaderRow >
172+ < HeaderCellPosition > 位置</ HeaderCellPosition >
173+ { displayLanguages . map ( ( lang ) => (
174+ < HeaderCellLang key = { lang } >
175+ { languageMap [ lang as keyof typeof languageMap ] }
176+ </ HeaderCellLang >
177+ ) ) }
178+ </ HeaderRow >
179+ { items . map ( ( item , idx ) => {
180+ const isHighlight =
181+ item . sheet === props . highlightItem ?. sheet &&
182+ item . rowId === props . highlightItem ?. rowId
183+ return (
184+ < ItemRow
95185 key = { `${ item . sheet } -${ item . rowId } -${ idx } ` }
96- className = {
97- item . sheet === props . highlightItem ?. sheet &&
98- item . rowId === props . highlightItem ?. rowId
99- ? 'highlight-row'
100- : ''
101- }
186+ $highlight = { isHighlight }
187+ data-highlight-row = { isHighlight ? 'true' : undefined }
102188 >
103- < td >
189+ < CellPosition >
104190 { item . sheet } #{ item . rowId }
105191 < br />
106192 < LinkButton onClick = { ( ) => props . onContextButtonClick ?.( item ) } >
107193 搜索上下文
108194 </ LinkButton >
109- </ td >
195+ </ CellPosition >
110196 { displayLanguages . map ( ( lang ) => {
111197 const value = item . values [ lang ]
198+ const label = languageMap [ lang as keyof typeof languageMap ]
112199 return (
113- < td key = { lang } >
114- { value ? highlightText ( value , keyword ) : '' }
115- </ td >
200+ < CellLang key = { lang } data-label = { label } >
201+ < div > { value ? highlightText ( value , keyword ) : '' } </ div >
202+ </ CellLang >
116203 )
117204 } ) }
118- </ tr >
119- ) ) }
120- </ HighlightedTbody >
121- </ StyledHtmlTable >
205+ </ ItemRow >
206+ )
207+ } ) }
208+ </ ListContainer >
122209 </ ScrollableContainer >
123210 )
124211}
0 commit comments