e72ec608f4
#95 #95 #95 #95 #95 Merge remote-tracking branch 'origin/main' into feature/095 #95 #95 #95 Co-authored-by: miteruzo <miteruzo@naver.com> Reviewed-on: #311
71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
import { motion } from 'framer-motion'
|
|
import { useRef } from 'react'
|
|
import { useLocation } from 'react-router-dom'
|
|
|
|
import PrefetchLink from '@/components/PrefetchLink'
|
|
import { useSharedTransitionStore } from '@/stores/sharedTransitionStore'
|
|
|
|
import type { FC, MouseEvent } from 'react'
|
|
|
|
import type { Post } from '@/types'
|
|
|
|
type Props = { posts: Post[]
|
|
onClick?: (event: MouseEvent<HTMLElement>) => void }
|
|
|
|
|
|
export default (({ posts, onClick }: Props) => {
|
|
const location = useLocation ()
|
|
|
|
const setForLocationKey = useSharedTransitionStore (s => s.setForLocationKey)
|
|
|
|
const cardRef = useRef<HTMLDivElement> (null)
|
|
|
|
return (
|
|
<div className="flex flex-wrap gap-6 p-4">
|
|
{posts.map ((post, i) => {
|
|
const sharedId = `page-${ post.id }`
|
|
const layoutId = sharedId
|
|
|
|
return (
|
|
<PrefetchLink
|
|
to={`/posts/${ post.id }`}
|
|
key={post.id}
|
|
className="w-40 h-40"
|
|
state={{ sharedId }}
|
|
onClick={e => {
|
|
setForLocationKey (location.key, sharedId)
|
|
onClick?.(e)
|
|
}}>
|
|
<motion.div
|
|
ref={cardRef}
|
|
layoutId={layoutId}
|
|
className="w-full h-full overflow-hidden rounded-xl shadow
|
|
transform-gpu will-change-transform"
|
|
whileHover={{ scale: 1.02 }}
|
|
onLayoutAnimationStart={() => {
|
|
if (!(cardRef.current))
|
|
return
|
|
|
|
cardRef.current.style.position = 'relative'
|
|
cardRef.current.style.zIndex = '9999'
|
|
}}
|
|
onLayoutAnimationComplete={() => {
|
|
if (!(cardRef.current))
|
|
return
|
|
|
|
cardRef.current.style.zIndex = ''
|
|
cardRef.current.style.position = ''
|
|
}}
|
|
transition={{ layout: { duration: .2, ease: 'easeOut' } }}>
|
|
<img src={post.thumbnail || post.thumbnailBase || undefined}
|
|
alt={post.title || post.url}
|
|
title={post.title || post.url || undefined}
|
|
loading={i < 12 ? 'eager' : 'lazy'}
|
|
decoding="async"
|
|
className="object-cover w-full h-full"/>
|
|
</motion.div>
|
|
</PrefetchLink>)
|
|
})}
|
|
</div>)
|
|
}) satisfies FC<Props>
|