ぼざクリタグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

71 lines
2.0 KiB

  1. import { motion } from 'framer-motion'
  2. import { useRef } from 'react'
  3. import { useLocation } from 'react-router-dom'
  4. import PrefetchLink from '@/components/PrefetchLink'
  5. import { useSharedTransitionStore } from '@/stores/sharedTransitionStore'
  6. import type { FC, MouseEvent } from 'react'
  7. import type { Post } from '@/types'
  8. type Props = { posts: Post[]
  9. onClick?: (event: MouseEvent<HTMLElement>) => void }
  10. export default (({ posts, onClick }: Props) => {
  11. const location = useLocation ()
  12. const setForLocationKey = useSharedTransitionStore (s => s.setForLocationKey)
  13. const cardRef = useRef<HTMLDivElement> (null)
  14. return (
  15. <div className="flex flex-wrap gap-6 p-4">
  16. {posts.map ((post, i) => {
  17. const sharedId = `page-${ post.id }`
  18. const layoutId = sharedId
  19. return (
  20. <PrefetchLink
  21. to={`/posts/${ post.id }`}
  22. key={post.id}
  23. className="w-40 h-40"
  24. state={{ sharedId }}
  25. onClick={e => {
  26. setForLocationKey (location.key, sharedId)
  27. onClick?.(e)
  28. }}>
  29. <motion.div
  30. ref={cardRef}
  31. layoutId={layoutId}
  32. className="w-full h-full overflow-hidden rounded-xl shadow
  33. transform-gpu will-change-transform"
  34. whileHover={{ scale: 1.02 }}
  35. onLayoutAnimationStart={() => {
  36. if (!(cardRef.current))
  37. return
  38. cardRef.current.style.position = 'relative'
  39. cardRef.current.style.zIndex = '9999'
  40. }}
  41. onLayoutAnimationComplete={() => {
  42. if (!(cardRef.current))
  43. return
  44. cardRef.current.style.zIndex = ''
  45. cardRef.current.style.position = ''
  46. }}
  47. transition={{ type: 'spring', stiffness: 500, damping: 40, mass: .5 }}>
  48. <img src={post.thumbnail || post.thumbnailBase || undefined}
  49. alt={post.title || post.url}
  50. title={post.title || post.url || undefined}
  51. loading={i < 12 ? 'eager' : 'lazy'}
  52. decoding="async"
  53. className="object-cover w-full h-full"/>
  54. </motion.div>
  55. </PrefetchLink>)
  56. })}
  57. </div>)
  58. }) satisfies FC<Props>