1
1
"use client" ;
2
2
3
- import Context from "@/app/components/Context" ;
3
+ import Picture from "next-export-optimize-images/image" ;
4
+ import type { StaticImageData } from "next/image" ;
4
5
import Link from "next/link" ;
5
6
import React , { useContext , useState } from "react" ;
6
7
import { BiLinkExternal , BiSolidLock } from "react-icons/bi" ;
7
8
import { IoEyeOffOutline } from "react-icons/io5" ;
8
9
9
- export type Article = {
10
+ import Context from "@/app/components/Context" ;
11
+
12
+ export type PreviewProps = {
10
13
title : string ;
11
- description : string ;
12
- metadata : {
13
- href ?: string ;
14
- author : string ;
15
- date : string ;
16
- } ;
14
+ summary : string ;
15
+ href ?: string ;
16
+ cover : StaticImageData | string ;
17
+ coverAlt : string ;
18
+ author : string ;
19
+ date : string ;
17
20
hidden : boolean ;
18
21
} ;
19
22
@@ -30,25 +33,17 @@ function MaybeLink({
30
33
return < React . Fragment > { children } </ React . Fragment > ;
31
34
}
32
35
33
- export default function ArticlePreview ( {
34
- title,
35
- description,
36
- metadata,
37
- hidden,
38
- canvasRef,
39
- } : Article & {
40
- canvasRef : ( ref : HTMLCanvasElement ) => void ;
41
- } ) {
36
+ export default function ArticlePreview ( props : PreviewProps ) {
42
37
const { canHover } = useContext ( Context ) ;
43
38
const [ shaking , setShaking ] = useState ( false ) ;
44
39
const classShaking = shaking ? "animate-shake" : "" ;
45
40
const [ locking , setLocking ] = useState ( false ) ;
46
41
47
42
return (
48
43
< div
49
- className = { `article-preview ${ hidden && "article-hidden" } transition-transform duration-300 hover:scale-105 ${ hidden ? "hover:cursor-not-allowed" : "hover:cursor-pointer" } ` }
44
+ className = { `article-preview ${ props . hidden && "article-hidden" } transition-transform duration-300 hover:scale-105 ${ props . hidden ? "hover:cursor-not-allowed" : "hover:cursor-pointer" } ` }
50
45
onClick = { ( e ) => {
51
- if ( ! hidden ) {
46
+ if ( ! props . hidden ) {
52
47
return ;
53
48
}
54
49
if ( ! canHover ) {
@@ -61,52 +56,63 @@ export default function ArticlePreview({
61
56
e . preventDefault ( ) ;
62
57
} }
63
58
>
64
- < MaybeLink href = { metadata . href ?? "" } >
59
+ < MaybeLink href = { props . href ?? "" } >
65
60
< div
66
61
style = { {
67
62
backgroundColor : "oklch(from var(--element) l c h / 0.2)" ,
68
63
opacity : locking ? 1 : undefined ,
69
64
} }
70
- className = { `article-preview-card relative flex aspect-16/10 h-auto w-full flex-col items-end justify-between rounded-xl px-6 py-4 transition select-none ${ hidden && "opacity-85 grayscale-32" } ` }
71
- title = { hidden ? undefined : title }
65
+ className = { `article-preview-card relative aspect-16/10 h-auto w-full rounded-xl px-6 py-4 transition select-none ${ props . hidden ? "opacity-85 grayscale-32" : "" } ` }
72
66
>
73
- < canvas
74
- className = "absolute inset-0 h-full w-full rounded-xl object-cover"
75
- ref = { canvasRef }
67
+ < Picture
68
+ className = "absolute inset-0 z-0 h-full w-full rounded-xl object-cover"
69
+ sizes = "100vw, (min-width: 768px) 50vw, (min-width: 1024px) 33vw"
70
+ src = { props . cover }
71
+ alt = { props . title }
72
+ width = { 1600 }
73
+ height = { 1000 }
76
74
/>
77
- { hidden && (
75
+ { props . hidden && (
78
76
< IoEyeOffOutline
79
77
className = { `article-preview-card-lock absolute top-1/2 left-1/2 -translate-1/2 text-surface ${ locking ? "opacity-100" : "opacity-0" } h-12 w-12 transition-opacity duration-300` }
80
78
/>
81
79
) }
82
- < span className = { `font-theme-sans text-xs ${ hidden && "opacity-40" } ` } >
83
- [ { metadata . date } ]
84
- </ span >
85
- < span className = { `font-theme-sans text-xs ${ hidden && "opacity-40" } ` } >
86
- by [ { metadata . author } ]
87
- </ span >
88
80
</ div >
89
81
< h2
90
- className = { `mt-4 mb-2 flex justify-between font-theme-sans text-xl transition-all duration-300 ${ hidden && "break-words opacity-35" } ` }
82
+ className = { `mt-4 mb-2 flex justify-between transition-all duration-300 ${ props . hidden && "break-words opacity-35" } ` }
91
83
style = { { WebkitTextStrokeWidth : "0.01em" } }
92
84
>
93
85
< span
94
- className = { `article-preview-title mx-3 font-theme-sans font-medium ${ classShaking } ` }
95
- onAnimationEnd = { ( ) => hidden && ! canHover && setShaking ( false ) }
86
+ className = { `article-preview-title mx-3 font-theme-serif text-lg font-semibold lg:text-xl ${ classShaking } ` }
87
+ onAnimationEnd = { ( ) =>
88
+ props . hidden && ! canHover && setShaking ( false )
89
+ }
96
90
>
97
- { title }
91
+ { props . title }
98
92
</ span >
99
- < span className = "mx-5 mt-1 font-light " >
100
- { hidden ? < BiSolidLock /> : < BiLinkExternal /> }
93
+ < span className = "mx-5 mt-1" >
94
+ { props . hidden ? < BiSolidLock /> : < BiLinkExternal /> }
101
95
</ span >
102
96
</ h2 >
103
97
</ MaybeLink >
104
98
< hr className = "mb-2 h-px border-0 bg-element opacity-15" />
105
99
< p
106
- className = { `font-theme-sans text-sm font-light ${ hidden && "break-words opacity-20" } ` }
100
+ className = { `text-justify font-theme-sans text-base font-light ${ props . hidden && "break-words opacity-20" } ` }
107
101
>
108
- { description }
102
+ { props . summary }
109
103
</ p >
104
+ < div className = "mt-4 flex justify-between" >
105
+ < span
106
+ className = { `font-theme-serif text-base text-raisin-500 dark:text-stone-500 ${ props . hidden ? "opacity-40" : "" } ` }
107
+ >
108
+ By { props . author }
109
+ </ span >
110
+ < span
111
+ className = { `font-theme-serif text-base text-raisin-500 dark:text-stone-500 ${ props . hidden ? "opacity-40" : "" } ` }
112
+ >
113
+ { props . date }
114
+ </ span >
115
+ </ div >
110
116
</ div >
111
117
) ;
112
118
}
0 commit comments