Skip to content

Commit

Permalink
Merge pull request #2 from goodchuck/develop
Browse files Browse the repository at this point in the history
feat & fix & chore : 24/05/27 일괄 커밋
  • Loading branch information
goodchuck authored May 27, 2024
2 parents d80def2 + cc081f6 commit ff377a4
Show file tree
Hide file tree
Showing 20 changed files with 630 additions and 43 deletions.
60 changes: 60 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@ant-design/icons": "^5.3.6",
"@faker-js/faker": "^8.4.1",
"antd": "^5.16.2",
"flubber": "^0.4.2",
"framer-motion": "^11.2.6",
"next": "14.2.1",
"react": "^18",
Expand Down
Binary file added public/algorithm/profile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 14 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { Metadata } from "next";
// import { Inter } from "next/font/google";
import "./globals.css";
import LoadingManager from "@/components/LoadingManager/LoadingManager";
import { Suspense } from "react";

// const inter = Inter({ subsets: ["latin"] });

Expand All @@ -14,10 +16,21 @@ export default function RootLayout({
}: Readonly<{
children: React.ReactNode;
}>) {

return (
<html lang="en">
{/* <body className={inter.className}>{children}</body> */}
<body>{children}</body>

<body>
<Suspense fallback={<div>Loading...</div>}>
<LoadingManager>
{children}
</LoadingManager>
</Suspense>

</body>


</html>
);
}
165 changes: 165 additions & 0 deletions src/components/ImageSlider/ImageSlider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
"use client";
// src/components/ImageSlider/ImageSlider.tsx
import { useEffect, useState, useRef, CSSProperties } from 'react';
import { motion, useAnimation } from 'framer-motion';
import styled from 'styled-components';

const Container = styled.div`
display: flex;
overflow: hidden;
width: 100%;
height: calc(100vh - 72px);
position: relative;
/* opacity: 0.7; */
`;

const Slide = styled(motion.div)`
min-width: 100%;
height: 100%;
background-size: contain; /* 이미지 전체가 보이도록 설정 */
background-repeat: no-repeat;
background-position: center;
position: relative;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 5rem;
font-weight: bold;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 1);
`;

const Title = styled.div<{ customStyle: CSSProperties }>`
white-space: pre-line; /* 줄바꿈 적용 */
text-align: center; /* 중앙 정렬 */
font-size: ${(props) => props.customStyle.fontSize || '5rem'};
`;

interface Image {
title: string;
src?: string;
duration: number;
style: CSSProperties;
}

const images: Image[] = [
{
title: '자동화 - 네이버/티스토리 GPT기반 내용 자동 포스팅',
src: '/projects/autopost/category/autopostShort.gif',
duration: 20000,
style: { fontSize: '5rem' }
},
{
title: '알고리즘 - 골드 1',
src: '/algorithm/profile.png',
duration: 4000,
style: { fontSize: '5rem' }
},
{
title: 'AI - ChatGPT 기반 PDF 문제 생성기',
src: '/projects/PDFProblem/image4.png',
duration: 4000,
style: { fontSize: '5rem' }
},
{
title: `프론트 개발
프로젝트 : 3D 어노테이션 툴 - 자율주행 정답데이터`,
src: '/projects/Dorosee3DTool/Dorosee3DTool1.png',
duration: 4000,
style: { fontSize: '5rem' }
},
{
title: `프론트 개발
프로젝트 : 4S - 삼성전자 사우디 건설 고도화 프로젝트 `,
src: '/projects/4S/4S-1.png',
duration: 4000,
style: { fontSize: '5rem' }
},
{
title: `프론트 개발
프로젝트 : ROADPMS - AI 도로 하자 검수`,
src: '/projects/ROADPMS/ROADPMS3.png',
duration: 4000,
style: { fontSize: '5rem' }
},
{
title: `안녕하세요 3년차 프론트엔드개발자 양태현입니다!
알고리즘, 웹크롤링, 자동화, AI, 개발 등등 관심이 많습니다!
저에관한 내용을 더 보고 싶으시다면 스크롤 다운을 해주세요!`,
src: '',
style: {
fontSize: '3rem'
},
duration: 10000
}
];

const ImageSlider = () => {
const controls = useAnimation();
const [currentIndex, setCurrentIndex] = useState(0);
const animationFrameId = useRef<number | null>(null);
const startTime = useRef<number | null>(null);

useEffect(() => {
let isMounted = true;

const update = (timestamp: number) => {
if (!startTime.current) {
startTime.current = timestamp;
}

const elapsed = timestamp - startTime.current;
const currentImage = images[currentIndex];

if (elapsed >= currentImage.duration) {
startTime.current = timestamp;
setCurrentIndex((prevIndex) => (prevIndex + 1) % images.length);
}

if (isMounted) {
animationFrameId.current = requestAnimationFrame(update);
}
};

const sequence = async () => {
while (isMounted) {
const currentImage = images[currentIndex];
await controls.start({
x: `-${currentIndex * 100}%`,
transition: {
type: 'spring',
stiffness: 500,
damping: 20,
},
});
animationFrameId.current = requestAnimationFrame(update);
}
};

sequence();

return () => {
isMounted = false; // 컴포넌트 언마운트 시 플래그를 false로 설정하여 애니메이션 정지
if (animationFrameId.current) {
cancelAnimationFrame(animationFrameId.current);
}
};
}, [controls, currentIndex]);

return (
<Container>
<motion.div
style={{ display: 'flex', width: `${images.length * 100}%` }}
animate={controls}
>
{images.map((image, index) => (
<Slide key={index} style={{ backgroundImage: `url(${image.src})` }}>
<Title customStyle={image.style}>{image.title}</Title>
</Slide>
))}
</motion.div>
</Container>
);
};

export default ImageSlider;
64 changes: 64 additions & 0 deletions src/components/Loading/Dots/LoadingDots.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// src/components/Loading/Loading.tsx
import styled from 'styled-components';
import { motion } from 'framer-motion';

const LoadingContainer = styled(motion.div)`
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
position: fixed;
top: 0;
left: 0;
background: rgba(255, 255, 255, 1);
z-index: 1000;
`;

const DotsWrapper = styled.div`
display: flex;
gap: 0.5rem;
`;

const Dot = styled(motion.div)`
width: 1rem;
height: 1rem;
background: #000;
border-radius: 50%;
`;

const loadingContainerVariants = {
start: { opacity: 1 },
end: { opacity: 0, transition: { duration: 0.5, delay: 1.5 } }
};

const dotVariants = {
start: { y: "0%" },
end: {
y: ["0%", "100%", "0%"],
transition: {
duration: 0.6,
repeat: Infinity,
ease: "easeInOut",
staggerChildren: 0.2
}
}
};

const LoadingDots = () => {
return (
<LoadingContainer
variants={loadingContainerVariants}
initial="start"
animate="end"
>
<DotsWrapper>
<Dot variants={dotVariants} />
<Dot variants={dotVariants} />
<Dot variants={dotVariants} />
</DotsWrapper>
</LoadingContainer>
);
};

export default LoadingDots;
Loading

0 comments on commit ff377a4

Please sign in to comment.