@@ -16,7 +16,7 @@ import { languageAtom, useTranslation } from '../i18n/i18n'
16
16
import { createCustomLevel , findLevelByStageName } from '../models/level'
17
17
import { getLocalizedOperatorName } from '../models/operator'
18
18
import { Paragraphs } from './Paragraphs'
19
- import { ReLinkDiv } from './ReLinkDiv '
19
+ import { ReLinkRenderer } from './ReLink '
20
20
import { UserName } from './UserName'
21
21
import { EDifficulty } from './entity/EDifficulty'
22
22
import { EDifficultyLevel , NeoELevel } from './entity/ELevel'
@@ -36,101 +36,105 @@ export const NeoOperationCard = ({
36
36
const { data : levels } = useLevels ( )
37
37
38
38
return (
39
- < Card interactive = { true } elevation = { Elevation . TWO } className = "relative" >
40
- < ReLinkDiv
39
+ < li className = "relative" >
40
+ < ReLinkRenderer
41
41
search = { { op : operation . id } }
42
- className = "h-full flex flex-col gap-2"
43
- >
44
- < div className = "flex" >
45
- < Tooltip2
46
- content = { operation . parsedContent . doc . title }
47
- className = "grow flex-1 whitespace-nowrap overflow-hidden text-ellipsis"
42
+ render = { ( { onClick, onKeyDown } ) => (
43
+ < Card
44
+ interactive
45
+ className = "h-full flex flex-col gap-2"
46
+ elevation = { Elevation . TWO }
47
+ tabIndex = { 0 }
48
+ onClick = { onClick }
49
+ onKeyDown = { onKeyDown }
48
50
>
49
- < H4 className = "p-0 m-0 mr-20 flex items-center overflow-hidden" >
50
- < span className = "whitespace-nowrap overflow-hidden text-ellipsis" >
51
- { operation . parsedContent . doc . title }
52
- </ span >
53
- { operation . status === CopilotInfoStatusEnum . Private && (
54
- < Tag minimal className = "ml-2 shrink-0 font-normal opacity-75" >
55
- { t . components . OperationCard . private }
56
- </ Tag >
57
- ) }
58
- </ H4 >
59
- </ Tooltip2 >
60
- </ div >
61
- < div className = "flex items-center text-slate-900" >
62
- < div className = "flex flex-wrap" >
63
- < NeoELevel
64
- level = {
65
- findLevelByStageName (
66
- levels ,
67
- operation . parsedContent . stageName ,
68
- ) || createCustomLevel ( operation . parsedContent . stageName )
69
- }
70
- />
71
- < EDifficulty
72
- difficulty = {
73
- operation . parsedContent . difficulty ?? OpDifficulty . UNKNOWN
74
- }
75
- />
76
- </ div >
77
- </ div >
78
- < div className = "flex-1 flex flex-col gap-2 justify-center" >
79
- < div className = "text-gray-700 leading-normal" >
80
- < Paragraphs
81
- content = { operation . parsedContent . doc . details }
82
- limitHeight = { 21 * 13.5 } // 13 lines, 21px per line; the extra 0.5 line is intentional so the `mask` effect is obvious
83
- />
84
- </ div >
85
- < div >
86
- < div className = "text-sm text-zinc-600 dark:text-slate-100 mb-2 font-bold" >
51
+ < Tooltip2
52
+ content = { operation . parsedContent . doc . title }
53
+ className = "whitespace-nowrap overflow-hidden text-ellipsis"
54
+ >
55
+ < H4 className = "p-0 m-0 mr-20 flex items-center overflow-hidden" >
56
+ < span className = "whitespace-nowrap overflow-hidden text-ellipsis" >
57
+ { operation . parsedContent . doc . title }
58
+ </ span >
59
+ { operation . status === CopilotInfoStatusEnum . Private && (
60
+ < Tag minimal className = "ml-2 shrink-0 font-normal opacity-75" >
61
+ { t . components . OperationCard . private }
62
+ </ Tag >
63
+ ) }
64
+ </ H4 >
65
+ </ Tooltip2 >
66
+
67
+ < div className = "flex items-center text-slate-900" >
68
+ < NeoELevel
69
+ level = {
70
+ findLevelByStageName (
71
+ levels ,
72
+ operation . parsedContent . stageName ,
73
+ ) || createCustomLevel ( operation . parsedContent . stageName )
74
+ }
75
+ />
76
+ < EDifficulty
77
+ difficulty = {
78
+ operation . parsedContent . difficulty ?? OpDifficulty . UNKNOWN
79
+ }
80
+ />
81
+ </ div >
82
+
83
+ < div className = "grow text-gray-700 leading-normal" >
84
+ < Paragraphs
85
+ content = { operation . parsedContent . doc . details }
86
+ limitHeight = { 21 * 13.5 } // 13 lines, 21px per line; the extra 0.5 line is intentional so the `mask` effect is obvious
87
+ />
88
+ </ div >
89
+
90
+ < div className = "text-sm text-zinc-600 dark:text-slate-100 font-bold" >
87
91
{ t . components . OperationCard . operators_and_groups }
88
92
</ div >
89
93
< OperatorTags operation = { operation } />
90
- </ div >
91
- </ div >
92
94
93
- < div className = "flex" >
94
- < div className = "flex items-center gap-1.5" >
95
- < Icon icon = "star" />
96
- < OperationRating
97
- className = "text-sm"
98
- operation = { operation }
99
- layout = "horizontal"
100
- />
101
- </ div >
102
- < div className = "flex-1" />
95
+ < div className = "flex" >
96
+ < div className = "flex items-center gap-1.5" >
97
+ < Icon icon = "star" />
98
+ < OperationRating
99
+ className = "text-sm"
100
+ operation = { operation }
101
+ layout = "horizontal"
102
+ />
103
+ </ div >
104
+ < div className = "flex-1" />
103
105
104
- < Tooltip2
105
- placement = "top"
106
- content = { t . components . OperationCard . views_count ( {
107
- count : operation . views ,
108
- } ) }
109
- >
110
- < div >
111
- < Icon icon = "eye-open" className = "mr-1.5" />
112
- < span > { operation . views } </ span >
106
+ < Tooltip2
107
+ placement = "top"
108
+ content = { t . components . OperationCard . views_count ( {
109
+ count : operation . views ,
110
+ } ) }
111
+ >
112
+ < div >
113
+ < Icon icon = "eye-open" className = "mr-1.5" />
114
+ < span > { operation . views } </ span >
115
+ </ div >
116
+ </ Tooltip2 >
113
117
</ div >
114
- </ Tooltip2 >
115
- </ div >
116
118
117
- < div className = "flex" >
118
- < div >
119
- < Icon icon = "time" className = "mr-1.5" />
120
- < RelativeTime
121
- Tooltip2Props = { { placement : 'top' } }
122
- moment = { operation . uploadTime }
123
- />
124
- </ div >
125
- < div className = "flex-1" />
126
- < div className = "text-zinc-500" >
127
- < Icon icon = "user" className = "mr-1.5" />
128
- < UserName userId = { operation . uploaderId } >
129
- { operation . uploader }
130
- </ UserName >
131
- </ div >
132
- </ div >
133
- </ ReLinkDiv >
119
+ < div className = "flex" >
120
+ < div >
121
+ < Icon icon = "time" className = "mr-1.5" />
122
+ < RelativeTime
123
+ Tooltip2Props = { { placement : 'top' } }
124
+ moment = { operation . uploadTime }
125
+ />
126
+ </ div >
127
+ < div className = "flex-1" />
128
+ < div className = "text-zinc-500" >
129
+ < Icon icon = "user" className = "mr-1.5" />
130
+ < UserName userId = { operation . uploaderId } >
131
+ { operation . uploader }
132
+ </ UserName >
133
+ </ div >
134
+ </ div >
135
+ </ Card >
136
+ ) }
137
+ />
134
138
135
139
< CardActions
136
140
className = "absolute top-4 right-4"
@@ -139,7 +143,7 @@ export const NeoOperationCard = ({
139
143
selected = { selected }
140
144
onSelect = { onSelect }
141
145
/>
142
- </ Card >
146
+ </ li >
143
147
)
144
148
}
145
149
@@ -148,100 +152,106 @@ export const OperationCard = ({ operation }: { operation: Operation }) => {
148
152
const { data : levels } = useLevels ( )
149
153
150
154
return (
151
- < Card
152
- interactive = { true }
153
- elevation = { Elevation . TWO }
154
- className = "relative mb-4 sm:mb-2 last:mb-0"
155
- >
156
- < ReLinkDiv search = { { op : operation . id } } >
157
- < div className = "flex flex-wrap mb-4 sm:mb-2" >
158
- { /* title */ }
159
- < div className = "flex flex-col gap-3" >
160
- < div className = "flex gap-2" >
161
- < H4 className = "inline-block pb-1 border-b-2 border-zinc-200 border-solid mb-2" >
162
- { operation . parsedContent . doc . title }
163
- { operation . status === CopilotInfoStatusEnum . Private && (
164
- < Tag minimal className = "ml-2 font-normal opacity-75" >
165
- { t . components . OperationCard . private }
166
- </ Tag >
167
- ) }
168
- </ H4 >
169
- </ div >
170
- < H5 className = "flex items-center text-slate-900 -mt-3" >
171
- < EDifficultyLevel
172
- level = {
173
- findLevelByStageName (
174
- levels ,
175
- operation . parsedContent . stageName ,
176
- ) || createCustomLevel ( operation . parsedContent . stageName )
177
- }
178
- difficulty = { operation . parsedContent . difficulty }
179
- />
180
- </ H5 >
181
- </ div >
155
+ < li className = "mb-4 sm:mb-2 last:mb-0" >
156
+ < ReLinkRenderer
157
+ search = { { op : operation . id } }
158
+ render = { ( { onClick, onKeyDown } ) => (
159
+ < Card
160
+ interactive
161
+ elevation = { Elevation . TWO }
162
+ tabIndex = { 0 }
163
+ onClick = { onClick }
164
+ onKeyDown = { onKeyDown }
165
+ >
166
+ < div className = "flex flex-wrap mb-4 sm:mb-2" >
167
+ { /* title */ }
168
+ < div className = "flex flex-col gap-3" >
169
+ < div className = "flex gap-2" >
170
+ < H4 className = "inline-block pb-1 border-b-2 border-zinc-200 border-solid mb-2" >
171
+ { operation . parsedContent . doc . title }
172
+ { operation . status === CopilotInfoStatusEnum . Private && (
173
+ < Tag minimal className = "ml-2 font-normal opacity-75" >
174
+ { t . components . OperationCard . private }
175
+ </ Tag >
176
+ ) }
177
+ </ H4 >
178
+ </ div >
179
+ < H5 className = "flex items-center text-slate-900 -mt-3" >
180
+ < EDifficultyLevel
181
+ level = {
182
+ findLevelByStageName (
183
+ levels ,
184
+ operation . parsedContent . stageName ,
185
+ ) || createCustomLevel ( operation . parsedContent . stageName )
186
+ }
187
+ difficulty = { operation . parsedContent . difficulty }
188
+ />
189
+ </ H5 >
190
+ </ div >
182
191
183
- < div className = "grow basis-full xl:basis-0" />
192
+ < div className = "grow basis-full xl:basis-0" />
184
193
185
- { /* meta */ }
186
- < div className = "flex flex-wrap items-start gap-x-4 gap-y-1 text-zinc-500" >
187
- < div className = "flex items-center gap-1.5" >
188
- < Icon icon = "star" />
189
- < OperationRating
190
- className = "text-sm"
191
- operation = { operation }
192
- layout = "horizontal"
193
- />
194
- </ div >
194
+ { /* meta */ }
195
+ < div className = "flex flex-wrap items-start gap-x-4 gap-y-1 text-zinc-500" >
196
+ < div className = "flex items-center gap-1.5" >
197
+ < Icon icon = "star" />
198
+ < OperationRating
199
+ className = "text-sm"
200
+ operation = { operation }
201
+ layout = "horizontal"
202
+ />
203
+ </ div >
195
204
196
- < Tooltip2
197
- placement = "top"
198
- content = { t . components . OperationCard . views_count ( {
199
- count : operation . views ,
200
- } ) }
201
- >
202
- < div >
203
- < Icon icon = "eye-open" className = "mr-1.5" />
204
- < span > { operation . views } </ span >
205
- </ div >
206
- </ Tooltip2 >
205
+ < Tooltip2
206
+ placement = "top"
207
+ content = { t . components . OperationCard . views_count ( {
208
+ count : operation . views ,
209
+ } ) }
210
+ >
211
+ < div >
212
+ < Icon icon = "eye-open" className = "mr-1.5" />
213
+ < span > { operation . views } </ span >
214
+ </ div >
215
+ </ Tooltip2 >
207
216
208
- < div >
209
- < Icon icon = "time" className = "mr-1.5" />
210
- < RelativeTime
211
- Tooltip2Props = { { placement : 'top' } }
212
- moment = { operation . uploadTime }
213
- />
214
- </ div >
217
+ < div >
218
+ < Icon icon = "time" className = "mr-1.5" />
219
+ < RelativeTime
220
+ Tooltip2Props = { { placement : 'top' } }
221
+ moment = { operation . uploadTime }
222
+ />
223
+ </ div >
215
224
216
- < div >
217
- < Icon icon = "user" className = "mr-1.5" />
218
- < UserName userId = { operation . uploaderId } >
219
- { operation . uploader }
220
- </ UserName >
225
+ < div >
226
+ < Icon icon = "user" className = "mr-1.5" />
227
+ < UserName userId = { operation . uploaderId } >
228
+ { operation . uploader }
229
+ </ UserName >
230
+ </ div >
231
+ </ div >
221
232
</ div >
222
- </ div >
223
- </ div >
224
- < div className = "flex md:flex-row flex-col gap-4" >
225
- < div className = "text-gray-700 leading-normal md:w-1/2" >
226
- < Paragraphs
227
- content = { operation . parsedContent . doc . details }
228
- limitHeight = { 21 * 13.5 } // 13 lines, 21px per line; the extra 0.5 line is intentional so the `mask` effect is obvious
229
- />
230
- </ div >
231
- < div className = "md:w-1/2" >
232
- < div className = "text-sm text-zinc-600 dark:text-slate-100 mb-2 font-bold" >
233
- { t . components . OperationCard . operators_and_groups }
233
+ < div className = "flex md:flex-row flex-col gap-4" >
234
+ < div className = "text-gray-700 leading-normal md:w-1/2" >
235
+ < Paragraphs
236
+ content = { operation . parsedContent . doc . details }
237
+ limitHeight = { 21 * 13.5 } // 13 lines, 21px per line; the extra 0.5 line is intentional so the `mask` effect is obvious
238
+ />
239
+ </ div >
240
+ < div className = "md:w-1/2" >
241
+ < div className = "text-sm text-zinc-600 dark:text-slate-100 mb-2 font-bold" >
242
+ { t . components . OperationCard . operators_and_groups }
243
+ </ div >
244
+ < OperatorTags operation = { operation } />
245
+ </ div >
234
246
</ div >
235
- < OperatorTags operation = { operation } />
236
- </ div >
237
- </ div >
238
- </ ReLinkDiv >
239
-
247
+ </ Card >
248
+ ) }
249
+ />
240
250
< CardActions
241
251
className = "absolute top-4 xl:top-12 right-[18px]"
242
252
operation = { operation }
243
253
/>
244
- </ Card >
254
+ </ li >
245
255
)
246
256
}
247
257
0 commit comments