@@ -17,6 +17,7 @@ type Paper = {
17
17
star? : number
18
18
tags? : string []
19
19
paperUrl? : string // 新增论文链接字段
20
+ author? : string
20
21
}
21
22
index? : number
22
23
}
@@ -41,56 +42,47 @@ const starCount = data.star ? Math.min(Math.max(data.star, 0), 5) : 0
41
42
className
42
43
)}
43
44
>
44
- { /* Star 评分 - 右上角 + 编号 (仅在大屏幕显示) */ }
45
- {
46
- (starCount > 0 || typeof paper .index === ' number' ) && (
47
- <div class = ' absolute top-4 right-4 items-center gap-1 z-20 hidden md:flex top-right-rating' >
48
- { starCount > 0 && (
49
- <div class = ' flex gap-0.5' >
50
- { Array .from ({ length: 5 }).map ((_ , i ) => (
51
- <Icon
52
- name = ' star'
53
- class = { cn (
54
- ' size-4' ,
55
- i < starCount ? ' text-yellow-400' : ' text-zinc-200 dark:text-zinc-700'
56
- )}
57
- />
58
- ))}
59
- </div >
60
- )}
61
- { typeof paper .index === ' number' && (
62
- <span class = ' ml-2 text-xs text-zinc-300 dark:text-zinc-600 font-mono select-none' >
63
- No.{ String (paper .index ).padStart (2 , ' 0' )}
64
- </span >
65
- )}
45
+ { /* 主内容区*/ }
46
+ <div class =' flex flex-col flex-1 min-w-0 z-10' >
47
+ { /* 标题与右上角信息容器 */ }
48
+ <div class =' flex justify-between items-center' >
49
+ { /* 标题区域 */ }
50
+ <div class =' space-y-1 flex-1 min-w-0 pr-4' >
51
+ <h3 class =' text-lg font-medium text-zinc-900 dark:text-zinc-100 leading-tight m-0' >
52
+ { data .title }
53
+ </h3 >
54
+ {
55
+ data .subTitle && (
56
+ <p class = ' text-sm text-zinc-600 dark:text-zinc-400 leading-normal m-0' >
57
+ { data .subTitle }
58
+ </p >
59
+ )
60
+ }
66
61
</div >
67
- )
68
- }
69
62
70
- { /* 右下角倾斜卡片,仅主图标和链接 (仅在大屏幕显示) */ }
71
- <div class =' paper-card-icon-preview hidden md:block' >
72
- <div class =' paper-preview-container' >
73
- <Icon name ={ data .isbn ? ' paper_book' : ' paper_article' } class =' paper-icon' />
63
+ { /* Star 评分 - 右上角 + 编号 (仅在大屏幕显示) */ }
74
64
{
75
- data .paperUrl && (
76
- <a href = { data .paperUrl } target = ' _blank' rel = ' noopener noreferrer' class = ' paper-link' >
77
- View >>
78
- </a >
79
- )
80
- }
81
- </div >
82
- </div >
83
-
84
- { /* 主内容区 */ }
85
- <div class =' flex flex-col flex-1 min-w-0 z-10 pr-0 md:pr-20' >
86
- { /* 标题区域 */ }
87
- <div class =' space-y-1' >
88
- <h3 class =' text-lg font-medium text-zinc-900 dark:text-zinc-100 leading-tight m-0' >
89
- { data .title }
90
- </h3 >
91
- {
92
- data .subTitle && (
93
- <p class = ' text-sm text-zinc-600 dark:text-zinc-400 leading-normal m-0' >{ data .subTitle } </p >
65
+ (starCount > 0 || typeof paper .index === ' number' ) && (
66
+ <div class = ' flex items-center gap-1 z-20 hidden md:flex top-right-rating large-screen-stars' >
67
+ { starCount > 0 && (
68
+ <div class = ' flex gap-0.5' >
69
+ { Array .from ({ length: 5 }).map ((_ , i ) => (
70
+ <Icon
71
+ name = ' star'
72
+ class = { cn (
73
+ ' size-4' ,
74
+ i < starCount ? ' text-yellow-400' : ' text-zinc-200 dark:text-zinc-700'
75
+ )}
76
+ />
77
+ ))}
78
+ </div >
79
+ )}
80
+ { typeof paper .index === ' number' && (
81
+ <span class = ' ml-2 text-xs text-zinc-300 dark:text-zinc-600 font-mono select-none' >
82
+ No.{ String (paper .index ).padStart (2 , ' 0' )}
83
+ </span >
84
+ )}
85
+ </div >
94
86
)
95
87
}
96
88
</div >
@@ -168,7 +160,9 @@ const starCount = data.star ? Math.min(Math.max(data.star, 0), 5) : 0
168
160
}
169
161
170
162
{ /* 小屏幕底部信息行 */ }
171
- <div class =' mt-4 pt-3 border-t border-zinc-100 dark:border-zinc-800 flex items-center justify-between md:hidden' >
163
+ <div
164
+ class =' mt-4 pt-3 border-t border-zinc-100 dark:border-zinc-800 flex items-center justify-between md:hidden'
165
+ >
172
166
<div class =' flex items-center gap-3' >
173
167
{ /* 论文类型图标 */ }
174
168
<div class =' flex items-center gap-1 text-sm text-zinc-500 dark:text-zinc-400' >
@@ -178,125 +172,143 @@ const starCount = data.star ? Math.min(Math.max(data.star, 0), 5) : 0
178
172
{ /* 论文链接 */ }
179
173
{
180
174
data .paperUrl && (
181
- <a
182
- href = { data .paperUrl }
183
- target = ' _blank'
184
- rel = ' noopener noreferrer'
175
+ <a
176
+ href = { data .paperUrl }
177
+ target = ' _blank'
178
+ rel = ' noopener noreferrer'
185
179
class = ' text-xs text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-200 transition-colors'
186
180
>
187
181
View >>
188
182
</a >
189
183
)
190
184
}
191
185
</div >
192
-
186
+
193
187
{ /* 评分和编号 */ }
194
188
<div class =' flex items-center gap-2' >
195
189
{ /* 编号 */ }
196
- { typeof paper .index === ' number' && (
197
- <span class = ' text-xs text-zinc-400 dark:text-zinc-500 font-mono select-none' >
198
- No.{ String (paper .index ).padStart (2 , ' 0' )}
199
- </span >
200
- )}
190
+ {
191
+ typeof paper .index === ' number' && (
192
+ <span class = ' text-xs text-zinc-400 dark:text-zinc-500 font-mono select-none' >
193
+ No.{ String (paper .index ).padStart (2 , ' 0' )}
194
+ </span >
195
+ )
196
+ }
201
197
{ /* 评分 */ }
202
- { starCount > 0 && (
203
- <div class = ' flex gap-0.5' >
204
- { Array .from ({ length: 5 }).map ((_ , i ) => (
205
- <Icon
206
- name = ' star'
207
- class = { cn (
208
- ' size-3' ,
209
- i < starCount ? ' text-yellow-400' : ' text-zinc-200 dark:text-zinc-700'
210
- )}
211
- />
212
- ))}
213
- </div >
214
- )}
198
+ {
199
+ starCount > 0 && (
200
+ <div class = ' flex gap-0.5' >
201
+ { Array .from ({ length: 5 }).map ((_ , i ) => (
202
+ <Icon
203
+ name = ' star'
204
+ class = { cn (
205
+ ' size-3' ,
206
+ i < starCount ? ' text-yellow-400' : ' text-zinc-200 dark:text-zinc-700'
207
+ )}
208
+ />
209
+ ))}
210
+ </div >
211
+ )
212
+ }
215
213
</div >
216
214
</div >
217
215
</div >
216
+
217
+ <!-- 浮动卡片链接 -->
218
+ {
219
+ data .paperUrl && (
220
+ <a
221
+ href = { data .paperUrl }
222
+ target = ' _blank'
223
+ rel = ' noopener noreferrer'
224
+ class = ' paper-card-link-wrapper hidden md:flex'
225
+ aria-label = { ` View paper: ${data .title } ` }
226
+ >
227
+ <div class = ' paper-preview-container' >
228
+ <Icon name = { data .isbn ? ' paper_book' : ' paper_article' } class = ' paper-icon' />
229
+ <span class = ' paper-link-text' >View</span >
230
+ </div >
231
+ </a >
232
+ )
233
+ }
218
234
</Tag >
219
235
220
236
<style >
221
- .paper-card-icon-preview {
237
+ /* 确保小屏幕隐藏右上角评分和编号 */
238
+ @media (max-width: 767px) {
239
+ .top-right-rating {
240
+ display: none !important;
241
+ }
242
+ }
243
+
244
+ /* 浮动卡片链接容器 */
245
+ .paper-card-link-wrapper {
222
246
position: absolute;
223
- right: 1.2rem;
224
- bottom: 1.2rem;
225
- width: 6.5rem;
226
- height: 5.2rem;
227
- display: flex;
228
- align-items: flex-end;
229
- z-index: 15;
230
- pointer-events: none;
247
+ right: 1.5rem;
248
+ bottom: 0;
249
+ z-index: 10;
250
+ transform: translateY(35%);
251
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
252
+ text-decoration: none;
253
+ }
254
+
255
+ .group:hover .paper-card-link-wrapper {
256
+ transform: translateY(-10%) scale(1.03);
231
257
}
258
+
259
+ /* 卡片视觉样式 */
232
260
.paper-preview-container {
233
- position: relative;
234
- width: 100%;
235
- height: 100%;
236
261
display: flex;
237
262
flex-direction: column;
238
263
align-items: center;
239
- justify-content: flex-end;
264
+ justify-content: center;
265
+ gap: 0.25rem;
266
+ width: 5.5rem;
267
+ height: 5.5rem;
268
+ padding-bottom: 0.25rem;
240
269
border-radius: var(--radius);
241
- border: 1px solid #e2e8f0; /* 亮色下深灰 */
242
- background: var(--background);
243
- user-select: none;
244
- transform: scale(1) rotate(0.18rad) translateY(30%);
245
- transition: transform 300ms ease-out;
246
- will-change: transform;
247
- backface-visibility: hidden;
248
- padding: 0.25rem 0.5rem 0.5rem 0.5rem;
249
- pointer-events: auto;
250
- overflow: hidden;
270
+ border: 1px solid rgb(226, 232, 240);
271
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.05), 0 2px 4px -2px rgb(0 0 0 / 0.05);
272
+ transition: border-color 0.3s;
251
273
}
274
+
252
275
.dark .paper-preview-container {
253
- background: var(--background);
254
- border-color: #f3f4f6; /* 暗色下浅灰 */
276
+ border-color: rgb(39, 39, 42);
255
277
}
278
+
256
279
.group:hover .paper-preview-container {
257
- transform: scale(1.04) rotate(0) translateY(15%);
258
- transition: transform 400ms cubic-bezier(0, 0.9, 0.5, 1.35);
280
+ border-color: rgb(203, 213, 225);
259
281
}
260
- .paper-icon {
261
- width: 2.5rem;
262
- height: 2.5rem;
263
- color: var(--muted-foreground);
264
- margin-bottom: 0.15rem;
265
- z-index: 2;
282
+
283
+ .dark .group:hover .paper-preview-container {
284
+ border-color: rgb(63, 63, 70);
266
285
}
267
- .paper-link {
268
- display: flex;
269
- align-items: center ;
270
- font-size: 0.75rem ;
286
+
287
+ .paper-icon {
288
+ width: 2.25rem ;
289
+ height: 2.25rem ;
271
290
color: var(--muted-foreground);
272
- margin-top: 0.15rem;
273
- text-decoration: none;
274
- pointer-events: auto;
275
- transition: color 0.2s;
276
- z-index: 2;
291
+ transition: color 0.3s;
277
292
}
278
- .paper-link:hover {
293
+
294
+ .group:hover .paper-icon {
279
295
color: var(--foreground);
280
296
}
281
- /* 编号右上角淡色小号字体,主题色自适应 */
282
- .paper-index-no {
283
- margin-left: 0.5rem;
284
- font-size: 0.82rem;
297
+
298
+ .paper-link-text {
299
+ font-size: 0.75rem;
285
300
color: var(--muted-foreground);
286
- font-family: var(--font-mono, monospace);
287
- user-select: none;
288
- letter-spacing: 0.04em;
289
- font-weight: 500;
301
+ opacity: 0;
302
+ transform: translateY(5px);
303
+ transition:
304
+ opacity 0.2s ease-out 0.1s,
305
+ transform 0.2s ease-out 0.1s,
306
+ color 0.3s;
290
307
}
291
- /* 确保小屏幕隐藏右上角评分和编号 */
292
- @media (max-width: 767px) {
293
- .top-right-rating {
294
- display: none !important;
295
- }
296
-
297
- /* 强制隐藏倾斜卡片 */
298
- .paper-card-icon-preview {
299
- display: none !important;
300
- }
308
+
309
+ .group:hover .paper-link-text {
310
+ opacity: 1;
311
+ transform: translateY(0);
312
+ color: var(--foreground);
301
313
}
302
314
</style >
0 commit comments