11"use client" ;
22
3- import Context from "@/app/components/Context" ;
3+ import Picture from "next-export-optimize-images/image" ;
4+ import type { StaticImageData } from "next/image" ;
45import Link from "next/link" ;
56import React , { useContext , useState } from "react" ;
67import { BiLinkExternal , BiSolidLock } from "react-icons/bi" ;
78import { IoEyeOffOutline } from "react-icons/io5" ;
89
9- export type Article = {
10+ import Context from "@/app/components/Context" ;
11+
12+ export type PreviewProps = {
1013 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 ;
1720 hidden : boolean ;
1821} ;
1922
@@ -30,25 +33,17 @@ function MaybeLink({
3033 return < React . Fragment > { children } </ React . Fragment > ;
3134}
3235
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 ) {
4237 const { canHover } = useContext ( Context ) ;
4338 const [ shaking , setShaking ] = useState ( false ) ;
4439 const classShaking = shaking ? "animate-shake" : "" ;
4540 const [ locking , setLocking ] = useState ( false ) ;
4641
4742 return (
4843 < 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" } ` }
5045 onClick = { ( e ) => {
51- if ( ! hidden ) {
46+ if ( ! props . hidden ) {
5247 return ;
5348 }
5449 if ( ! canHover ) {
@@ -61,52 +56,63 @@ export default function ArticlePreview({
6156 e . preventDefault ( ) ;
6257 } }
6358 >
64- < MaybeLink href = { metadata . href ?? "" } >
59+ < MaybeLink href = { props . href ?? "" } >
6560 < div
6661 style = { {
6762 backgroundColor : "oklch(from var(--element) l c h / 0.2)" ,
6863 opacity : locking ? 1 : undefined ,
6964 } }
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" : "" } ` }
7266 >
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 }
7674 />
77- { hidden && (
75+ { props . hidden && (
7876 < IoEyeOffOutline
7977 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` }
8078 />
8179 ) }
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 >
8880 </ div >
8981 < 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" } ` }
9183 style = { { WebkitTextStrokeWidth : "0.01em" } }
9284 >
9385 < 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+ }
9690 >
97- { title }
91+ { props . title }
9892 </ 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 /> }
10195 </ span >
10296 </ h2 >
10397 </ MaybeLink >
10498 < hr className = "mb-2 h-px border-0 bg-element opacity-15" />
10599 < 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" } ` }
107101 >
108- { description }
102+ { props . summary }
109103 </ 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 >
110116 </ div >
111117 ) ;
112118}
0 commit comments