Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 'use client'
- import React, { useState, useEffect, useRef } from 'react'
- import { useSwipeable } from 'react-swipeable'
- import { ChevronLeft, ChevronRight } from 'lucide-react'
- import { motion, AnimatePresence } from 'framer-motion'
- const LinkedinPost = ({ imageUrl, scale }: { imageUrl: string; scale: number }) => {
- return (
- <div
- className={`card bg-base-100 shadow-xl overflow-hidden rounded-xl transition-all duration-300 ease-in-out`}
- style={{
- width: `${16 * scale}rem`,
- height: `${20 * scale}rem`,
- }}
- >
- <figure className="w-full h-full">
- <img
- src={imageUrl}
- alt="LinkedIn Post"
- className="w-full h-full object-cover"
- />
- </figure>
- </div>
- );
- };
- export default function Component({
- imageUrls = [
- 'https://i.pinimg.com/originals/ed/bf/0e/edbf0e545f2271a78539bd98f6ad5d46.jpg',
- 'https://i.pinimg.com/originals/f9/aa/7d/f9aa7d94a2f1943d77298b47ac58436d.jpg',
- 'https://i.pinimg.com/originals/9e/9c/83/9e9c83a0adaddfa5a17f011f085e2f4a.jpg',
- 'https://i.pinimg.com/originals/c5/f6/3b/c5f63b9f3e0a440d1865fd436c8b200d.jpg',
- 'https://i.pinimg.com/originals/b7/94/2d/b7942dd1574208c52367dd2ac4b98e9b.jpg',
- 'https://i.pinimg.com/originals/ba/fa/e8/bafae89ed636c0ad27397bd3e7080928.jpg',
- 'https://i.pinimg.com/originals/b8/ea/3e/b8ea3e03c2f6400cfb937a08767512e5.jpg',
- 'https://i.pinimg.com/originals/66/76/94/6676940d87c357f2c9453776c99f3365.jpg',
- 'https://i.pinimg.com/originals/f1/26/37/f12637ae012e4eb535026c7972369427.jpg',
- 'https://i.pinimg.com/originals/bb/85/be/bb85be6a6f012df2acbdef627f6fc613.jpg',
- 'https://i.pinimg.com/originals/a3/f9/9f/a3f99f8b8fa473e698f12ebc09406f59.jpg',
- 'https://i.pinimg.com/originals/8b/ef/d9/8befd98a4b8654649d6f4ef448b6470d.jpg',
- 'https://i.pinimg.com/originals/38/ea/d7/38ead79eb780667a0703e49075eba848.jpg',
- 'https://i.pinimg.com/originals/3d/70/73/3d70735cccdb05697be4180ca8c755a7.jpg',
- 'https://i.pinimg.com/originals/09/6e/17/096e172c0481c310dc53b1e970055489.jpg',
- 'https://i.pinimg.com/originals/07/58/91/07589144688de9c80e24e973229ee312.jpg',
- 'https://i.pinimg.com/originals/36/90/40/3690403b15b5ec4f1d74622167b15d12.jpg'
- ]
- }: { imageUrls?: string[] }) {
- const [activeIndex, setActiveIndex] = useState(0)
- const [visiblePosts, setVisiblePosts] = useState<string[]>([])
- const carouselRef = useRef<HTMLDivElement>(null)
- useEffect(() => {
- const updateVisiblePosts = () => {
- const windowWidth = window.innerWidth
- let visibleCount = 5
- if (windowWidth < 640) visibleCount = 1
- else if (windowWidth < 1024) visibleCount = 3
- const newVisiblePosts = []
- for (let i = 0; i < visibleCount; i++) {
- const index = (activeIndex + i - Math.floor(visibleCount / 2) + imageUrls.length) % imageUrls.length
- newVisiblePosts.push(imageUrls[index])
- }
- setVisiblePosts(newVisiblePosts)
- }
- updateVisiblePosts()
- window.addEventListener('resize', updateVisiblePosts)
- return () => window.removeEventListener('resize', updateVisiblePosts)
- }, [activeIndex, imageUrls])
- useEffect(() => {
- const interval = setInterval(() => {
- setActiveIndex((prevIndex) => (prevIndex + 1) % imageUrls.length)
- }, 5000)
- return () => clearInterval(interval)
- }, [imageUrls.length])
- const handlers = useSwipeable({
- onSwipedLeft: () => setActiveIndex((prevIndex) => (prevIndex + 1) % imageUrls.length),
- onSwipedRight: () => setActiveIndex((prevIndex) => (prevIndex - 1 + imageUrls.length) % imageUrls.length),
- })
- const goToIndex = (index: number) => {
- setActiveIndex(index)
- }
- const renderPaginationIndicators = () => {
- const totalIndicators = Math.min(5, imageUrls.length)
- const startIndex = Math.max(0, Math.min(activeIndex - Math.floor(totalIndicators / 2), imageUrls.length - totalIndicators))
- return Array.from({ length: totalIndicators }, (_, i) => {
- const index = (startIndex + i) % imageUrls.length
- return (
- <motion.div
- key={index}
- initial={{ scale: 0.8 }}
- animate={{ scale: index === activeIndex ? 1.2 : 1 }}
- transition={{ duration: 0.2 }}
- >
- <button
- className={`btn btn-circle btn-xs ${index === activeIndex ? 'btn-primary' : 'btn-ghost'}`}
- onClick={() => goToIndex(index)}
- aria-label={`Go to slide ${index + 1}`}
- />
- </motion.div>
- )
- })
- }
- const getScale = (index: number) => {
- const middleIndex = Math.floor(visiblePosts.length / 2)
- if (index === middleIndex) return 1.2
- if (index === middleIndex - 1 || index === middleIndex + 1) return 1
- return 0.8
- }
- return (
- <div className="w-full max-w-6xl mx-auto p-8 pb-14 bg-gradient-to-r from-base-200 to-base-300 rounded-3xl shadow-lg" {...handlers}>
- <div className="relative overflow-hidden">
- <div
- ref={carouselRef}
- className="flex justify-center items-center"
- >
- <AnimatePresence initial={false}>
- {visiblePosts.map((imageUrl, index) => (
- <motion.div
- key={`${activeIndex}-${index}`}
- className="mx-2"
- initial={{ opacity: 0, x: index === 0 ? -100 : index === visiblePosts.length - 1 ? 100 : 0 }}
- animate={{ opacity: 1, x: 0 }}
- exit={{ opacity: 0, x: index === 0 ? 100 : index === visiblePosts.length - 1 ? -100 : 0 }}
- transition={{ duration: 0.5 }}
- >
- <LinkedinPost imageUrl={imageUrl} scale={getScale(index)} />
- </motion.div>
- ))}
- </AnimatePresence>
- </div>
- <button
- className="btn btn-circle btn-sm absolute top-1/2 left-4 -translate-y-1/2 bg-base-100 hover:bg-base-200"
- onClick={() => setActiveIndex((prevIndex) => (prevIndex - 1 + imageUrls.length) % imageUrls.length)}
- aria-label="Previous slide"
- >
- <ChevronLeft className="h-4 w-4" />
- </button>
- <button
- className="btn btn-circle btn-sm absolute top-1/2 right-4 -translate-y-1/2 bg-base-100 hover:bg-base-200"
- onClick={() => setActiveIndex((prevIndex) => (prevIndex + 1) % imageUrls.length)}
- aria-label="Next slide"
- >
- <ChevronRight className="h-4 w-4" />
- </button>
- </div>
- <div className="flex justify-center mt-6 space-x-2">
- {renderPaginationIndicators()}
- </div>
- </div>
- )
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement