Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { withSentryConfig } from "@sentry/nextjs";
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
deviceSizes: [640, 750, 828, 1080, 1280, 1920],
unoptimized: true,
remotePatterns: [
{
Expand Down
67 changes: 37 additions & 30 deletions src/app/(home)/_components/MainBanner.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,52 @@
"use client";

import "swiper/css";
import "swiper/css/effect-fade";

import { AnimatePresence, motion } from "framer-motion";
import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";

import { MAIN_BANNER_ITEMS } from "@/constants/ui";

const MainBanner = () => {
const animatedTexts = ["러닝", "게임", "음악", "치맥"];
const [currentIndex, setCurrentIndex] = useState(0);

useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex(prevIndex => (prevIndex + 1) % animatedTexts.length);
}, 3000); // 3초마다 텍스트,슬라이드 변경
setCurrentIndex(prev => (prev + 1) % MAIN_BANNER_ITEMS.length);
}, 3000);

return () => clearInterval(interval);
}, [animatedTexts.length]);
}, []);

return (
<section className="relative h-[50vh] max-h-[500px] w-full overflow-hidden md:h-[90vh] md:max-h-[1080px]">
<AnimatePresence mode="popLayout">
<motion.div
key={currentIndex}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.9, ease: "easeInOut" }}
className="relative h-full w-full"
>
<Image
src={`/images/main_slide${currentIndex + 1}.jpg`}
alt={`main_banner_${animatedTexts[currentIndex]}`}
fill
sizes="(max-width: 1280px) 100vw, 1280px"
className="object-cover"
priority
/>
</motion.div>
</AnimatePresence>
<div className="base-wrap absolute bottom-0 left-0 right-0 z-10 flex h-full flex-col justify-end gap-5 p-10 px-5 text-3xl font-bold text-white md:py-28 md:text-5xl md:font-extrabold">
<Link
href={MAIN_BANNER_ITEMS[currentIndex].link}
className="relative h-[50vh] max-h-[500px] w-full overflow-hidden bg-gray-500 md:h-[90vh] md:max-h-[1080px]"
>
{/* 이미지 슬라이드 영역 */}
<div className="relative h-full w-full">
{MAIN_BANNER_ITEMS.map((item, index) => (
<div
key={index}
className={`absolute inset-0 transition-opacity duration-1000 ${
index === currentIndex ? "z-10 opacity-100" : "z-0 opacity-0"
}`}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 애니메이션 방법도 있군요 👍

>
<Image
src={item.image}
alt={`main_banner_${item.text}`}
fill
sizes="(max-width: 1280px) 100vw, 1280px"
className="object-cover"
placeholder="blur"
priority={index === 0}
/>
</div>
))}
</div>

{/* 텍스트 애니메이션 영역 */}
<div className="base-wrap absolute bottom-0 left-0 right-0 z-20 flex h-full flex-col justify-end gap-5 p-10 px-5 text-3xl font-bold text-white md:py-28 md:text-5xl md:font-extrabold">
<p>{"지친 일상을 잠시 멈추고"}</p>
<p className="overflow-hidden">
{"함께 "}
Expand All @@ -51,16 +57,17 @@ const MainBanner = () => {
initial={{ y: "110%" }}
animate={{ y: "0%" }}
exit={{ y: "-120%" }}
transition={{ duration: 0.5, ease: "easeInOut" }}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transition을 줘도 사진 넘어가는거랑 글자 바뀌는 타이밍이 잘 맞던가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

타이밍은 잘 맞고 있습니다 머지하면 한번 확인부탁드려요!

className="block"
>
{animatedTexts[currentIndex]}
{MAIN_BANNER_ITEMS[currentIndex].text}
</motion.span>
</AnimatePresence>
</span>
{" 어떠세요?"}
</p>
</div>
</section>
</Link>
);
};

Expand Down
5 changes: 3 additions & 2 deletions src/app/(home)/_components/MainCarouselItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ const MainCarouselItem = ({ gathering }: IMainCarouselItemProps) => {
href={`/gathering/detail/${gathering.id}`}
className="flex flex-col gap-2"
>
<div className="relative h-[150px] overflow-hidden rounded-lg md:h-[200px] lg:h-[250px]">
<div className="relative h-[150px] overflow-hidden rounded-lg bg-gray-200 md:h-[200px] lg:h-[250px]">
<Image
src={gathering.image || "/images/gathering_default.jpeg"}
alt="carousel-item"
alt={`gathering image - [${gathering.name}]`}
fill
sizes="(max-width: 768px) 150px, (max-width: 1024px) 240px, 260px"
className="object-cover transition-all duration-300 hover:scale-110"
priority
/>
</div>
<p className="line-clamp-1 font-medium text-gray-900">{gathering.name}</p>
Expand Down
2 changes: 1 addition & 1 deletion src/app/(home)/_components/MainReviewContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const MainReviewContent = () => {
<div className="flex flex-col items-center justify-center gap-5 sm:flex-row">
<Image
src="/images/logo.png"
alt="logo"
alt="logo-image"
width={130}
height={60}
sizes="130px"
Expand Down
12 changes: 10 additions & 2 deletions src/app/(home)/_components/animations/MainAnimation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@
import dynamic from "next/dynamic";
import { memo, useEffect, useState } from "react";

const Lottie = dynamic(() => import("lottie-light-react"), { ssr: false });

import LoadingSpinner from "@/components/common/LoadingSpinner";

const Lottie = dynamic(() => import("lottie-light-react"), {
loading: () => (
<div className="flex h-[450px] w-[500px] items-center justify-center bg-gray-200 sm:h-[600px] md:h-full">
<LoadingSpinner size="lg" />
</div>
),
ssr: false,
});
interface IMainAnimationProps {
type: "online" | "offline";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const GatheringImage = ({ id }: IGatheringImageProps) => {
<DeadlineTag registrationEnd={dayjs(data?.registrationEnd)} />
<Image
src={data.image || "/images/gathering_default.jpeg"}
alt="gathering-image"
alt={`모임-[${data.name}] 이미지`}
fill
sizes="(max-width: 768px) 90vw, 40vw"
className="object-cover"
Expand Down
14 changes: 2 additions & 12 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
import "./globals.css";

import type { Metadata } from "next";
import dynamic from "next/dynamic";

import TokenValidator from "@/components/auth/TokenValidator";
import Footer from "@/components/layout/Footer";
import Header from "@/components/layout/Header";
import QueryProvider from "@/components/providers/QueryProvider";
import { FONT } from "@/constants/font";

const TokenValidator = dynamic(
() => import("@/components/auth/TokenValidator"),
{
ssr: false,
},
);

const Footer = dynamic(() => import("@/components/layout/Footer"), {
ssr: false,
});

export const metadata: Metadata = {
title: "PLAKE",
description:
Expand Down
1 change: 0 additions & 1 deletion src/assets/animations/offline.json

This file was deleted.

1 change: 0 additions & 1 deletion src/assets/animations/online.json

This file was deleted.

Binary file added src/assets/images/main_slide1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/main_slide2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/main_slide3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/main_slide4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/components/layout/MainCardImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ const MainCardImage = ({
registrationEnd,
}: IMainCardImageProps) => {
return (
<div className="relative h-[156px] w-full min-w-[280px] md:w-[280px] lg:w-[280px]">
<div className="relative h-[156px] w-full min-w-[280px] bg-gray-200 md:w-[280px] lg:w-[280px]">
<Image
src={image || "/images/gathering_default.jpeg"}
alt={image ? name : "모임 기본 이미지"}
className="h-full w-full object-cover"
fill
sizes="(max-width: 768px) 50vw"
></Image>
/>
<DeadlineTag registrationEnd={registrationEnd} />
</div>
);
Expand Down
29 changes: 29 additions & 0 deletions src/constants/ui.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
// 메인 배너 아이템
import mainBanner1 from "@/assets/images/main_slide1.jpg";
import mainBanner2 from "@/assets/images/main_slide2.jpg";
import mainBanner3 from "@/assets/images/main_slide3.jpg";
import mainBanner4 from "@/assets/images/main_slide4.jpg";

export const MAIN_BANNER_ITEMS = [
{
image: mainBanner1,
text: "러닝",
link: "/gathering/offline?type=exercise",
},
{
image: mainBanner2,
text: "게임",
link: "/gathering/online",
},
{
image: mainBanner3,
text: "음악",
link: "/gathering/offline?type=art",
},
{
image: mainBanner4,
text: "치맥",
link: "/gathering/offline?type=dining",
},
] as const;

// 메인 탭
export const MAIN_TAB = [
{ name: "오프라인", value: "", href: "/gathering/offline" },
Expand Down