Picture Replaced

This commit is contained in:
암냥 2025-03-07 18:07:37 +09:00
commit 607dd617f6
3 changed files with 57 additions and 84 deletions

View file

@ -1,63 +1,43 @@
import { useEffect } from 'react'; import { useEffect } from "react";
import Top from "@/components/Home/Top"; import Top from "@/components/Home/Top";
import About from "@/components/Home/About"; import About from "@/components/Home/About";
import Timeline from "@/components/Home/Timeline"; import Timeline from "@/components/Home/Timeline";
import Contact from '@/components/Home/Contact'; import Contact from "@/components/Home/Contact";
import Project from '@/components/Home/Project'; import Project from "@/components/Home/Project";
import './index.css'; import "./index.css";
export function App() { export function App() {
useEffect(() => { useEffect(() => {
// 초기 로드 시 hash에 맞게 스크롤 // img 위에서 스크롤 방지
const scrollToHash = () => { const handleWheel = (event) => {
const hash = window.location.hash.substring(1); if (event.target.tagName.toLowerCase() === "img") {
if (hash) { event.preventDefault();
const element = document.getElementById(hash);
if (element) {
setTimeout(() => {
element.scrollIntoView({ behavior: "smooth" });
}, 100); // 브라우저가 레이아웃을 그릴 시간을 줌
}
} }
}; };
scrollToHash();
// 스크롤 시 hash 업데이트 로직 document.addEventListener("wheel", handleWheel, { passive: false });
const sections = document.querySelectorAll(".section");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
window.history.replaceState(null, "", `#${entry.target.id}`);
}
});
},
{ threshold: 0.6 } // 60% 보이면 활성화
);
sections.forEach(section => observer.observe(section));
return () => { return () => {
sections.forEach(section => observer.unobserve(section)); document.removeEventListener("wheel", handleWheel);
}; };
}, []); }, []);
return ( return (
<div id="fullpage" className="bg-background text-foreground w-full"> <div id="fullpage" className="bg-background text-foreground w-full">
<div id="top" className="bg-background text-foreground w-full h-screen flex items-center justify-center section"> <div id="top" className="section">
<Top /> <Top />
</div> </div>
<div id="about" className="bg-background text-foreground w-full h-screen flex items-center justify-center section"> <div id="about" className="section">
<About /> <About />
</div> </div>
<div id="project" className="bg-background text-foreground w-full h-screen flex items-center justify-center section"> <div id="project" className="section">
<Project /> <Project />
</div> </div>
<div id="timeline" className="bg-background text-foreground w-full h-screen flex items-center justify-center section"> <div id="timeline" className="section">
<Timeline /> <Timeline />
</div> </div>
<div id="contact" className="bg-background text-foreground w-full h-screen flex items-center justify-center section"> <div id="contact" className="section">
<Contact /> <Contact />
</div> </div>
</div> </div>

View file

@ -1,13 +1,30 @@
import { import { useState } from "react";
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import "../../index.css"; import "../../index.css";
import Image from "../../profile.avif";
export default function Top() { export default function Top() {
const [mousePos, setMousePos] = useState({ x: 50, y: 50 });
const [scale, setScale] = useState(1.15);
const [isHovering, setIsHovering] = useState(false);
const handleMouseMove = (e) => {
const { left, top, width, height } = e.currentTarget.getBoundingClientRect();
const x = ((e.clientX - left) / width) * 100;
const y = ((e.clientY - top) / height) * 100;
setMousePos((prev) => ({
x: prev.x + (x - prev.x) * 0.1,
y: prev.y + (y - prev.y) * 0.1,
}));
};
const handleWheel = (e) => {
e.preventDefault();
setScale((prev) => {
const newScale = prev + e.deltaY * -0.0025;
return Math.min(Math.max(newScale, 1), 3);
});
};
return ( return (
<div className="bg-background text-foreground w-full h-screen flex items-center justify-center"> <div className="bg-background text-foreground w-full h-screen flex items-center justify-center">
<div className="flex flex-col md:flex-row w-full md:w-[50%] h-full py-16 md:py-32"> <div className="flex flex-col md:flex-row w-full md:w-[50%] h-full py-16 md:py-32">
@ -24,29 +41,24 @@ export default function Top() {
</p> </p>
</div> </div>
</div> </div>
<TooltipProvider delayDuration={0}> <div
<Tooltip> className="md:w-[55%] select-none p-5 md:p-0 w-full h-full flex justify-center md:justify-end items-end rounded-3xl mb-8 md:mb-0 overflow-hidden"
<TooltipTrigger asChild> onMouseMove={handleMouseMove}
<div className="md:w-[55%] select-none avatar-background w-full h-full flex justify-center md:justify-end items-end rounded-3xl mb-8 md:mb-0"> onMouseEnter={() => setIsHovering(true)}
<div className="w-full h-full flex justify-center md:justify-end items-end avatar-background-blur"> onMouseLeave={() => setIsHovering(false)}
onWheel={handleWheel}
>
<img <img
src={Image} src="https://f.imnya.ng/profile/b.avif"
className="w-[60%] max-w-[360px] select-none" alt="Me"
title="Special Thanks to @dob2_" className="w-full h-full object-cover rounded-3xl transition-transform duration-500 ease-out"
style={{
transform: `scale(${isHovering ? scale : 1})`,
transformOrigin: `${mousePos.x}% ${mousePos.y}%`,
}}
/> />
</div> </div>
</div> </div>
</TooltipTrigger>
<TooltipContent
align="end"
side="bottom"
className="px-2 py-1 text-xs"
>
Special Thanks to @dob2_
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</div> </div>
); );
} }

View file

@ -13,22 +13,3 @@
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.avatar-background {
background: none;
}
@media (min-width: 768px) {
.avatar-background {
position: relative;
overflow: hidden;
background-image: url("https://f.imnya.ng/profile/banner.CjixG8N2_15mivN.webp");
background-size: cover;
background-position: 400px center;
background-repeat: no-repeat;
background-attachment: fixed;
}
.avatar-background-blur {
backdrop-filter: blur(5px);
}
}