From e98c18828ff077950fe48d6fd60c71f81d247c9d Mon Sep 17 00:00:00 2001 From: SySagar Date: Mon, 26 Aug 2024 22:18:52 +0530 Subject: [PATCH] feat: useCursor --- src/app/home/HeroPage.tsx | 64 +++++++++++++++++++++++++++++++- src/app/home/components/Blog.tsx | 7 ++++ src/app/home/home.css | 14 +++++++ src/hooks/useCursor.tsx | 45 ++++++++++++++++++++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/hooks/useCursor.tsx diff --git a/src/app/home/HeroPage.tsx b/src/app/home/HeroPage.tsx index 3527dfe..abff26f 100644 --- a/src/app/home/HeroPage.tsx +++ b/src/app/home/HeroPage.tsx @@ -2,7 +2,7 @@ import { Skeleton, Divider, Stack, Typography } from "@mui/material"; import HeroBlog from "./components/HeroBlog"; import Blog from "./components/Blog"; import Sidebar from "./components/Sidebar"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import APIMethods from "../../lib/axios/api"; import { blogTypes } from "../blog/types/blogTypes"; import SentimentDissatisfiedIcon from "@mui/icons-material/SentimentDissatisfied"; @@ -10,6 +10,8 @@ import useSearchStore from "../../lib/store/useSearchStore"; import "./home.css"; import { useResponsive } from "../../hooks/useResponsive"; import AnimatePage from "../../layout/AnimatePage"; +import { useCursor } from "../../hooks/useCursor"; +import { Chip, Avatar } from "@mui/material"; export default function HeroPage() { const [loading, setLoading] = useState(true); @@ -28,6 +30,33 @@ export default function HeroPage() { }); }; + const { cursorData, handleMouseMove, handleMouseLeave, isFadingOut } = + useCursor(); + + const getRandomName = useMemo( + (nameList = ["Diksha", "Aman", "Ayushii", "Sagar", "Kartik"]) => { + const randomIndex = Math.floor(Math.random() * nameList.length); + return nameList[randomIndex]; + }, + [cursorData.visible], + ); + + const getRandomUrl = useMemo( + ( + nameList = [ + "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + "https://images.unsplash.com/photo-1534528741775-53994a69daeb?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + "https://images.unsplash.com/photo-1499996860823-5214fcc65f8f?q=80&w=1966&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + "https://images.unsplash.com/photo-1539571696357-5a69c17a67c6?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + "https://images.unsplash.com/photo-1526510747491-58f928ec870f?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + ], + ) => { + const randomIndex = Math.floor(Math.random() * nameList.length); + return nameList[randomIndex]; + }, + [cursorData.visible], + ); + useEffect(() => { fetchBLogs() .then(() => { @@ -59,9 +88,38 @@ export default function HeroPage() { marginTop={3} justifyContent={"center"} alignItems={"center"} + position={"relative"} gap={1} borderColor={"#A3A0B2"} > + {cursorData.visible && ( + + {getRandomName} + + } + avatar={ + + } + style={{ + position: "fixed", + zIndex: 100, + backgroundColor: "#87dcf1", + top: cursorData.y, + left: cursorData.x, + height: "40px", + width: "auto", + transform: "translate(20%, 20%)", + pointerEvents: "none", + }} + /> + )} + handleMouseMove(e, blog.title, blog.title) + } + onMouseLeave={handleMouseLeave} date={blog.date} title={blog.title} tags={blog.tags} diff --git a/src/app/home/components/Blog.tsx b/src/app/home/components/Blog.tsx index c57e211..72cd159 100644 --- a/src/app/home/components/Blog.tsx +++ b/src/app/home/components/Blog.tsx @@ -14,6 +14,8 @@ interface BlogTypes { blogId: string; image: string; likes: number; + onMouseMove: any; + onMouseLeave: any; } export default function Blog({ @@ -23,6 +25,8 @@ export default function Blog({ tags = ["india", "hello world"], blogId, image, + onMouseMove, + onMouseLeave, }: BlogTypes) { const navigate = useNavigate(); const isPhone = useMediaQuery("(max-width:800px)"); @@ -39,6 +43,8 @@ export default function Blog({ alignItems={"center"} position={"relative"} maxWidth={"300px"} + onMouseMove={onMouseMove} + onMouseLeave={onMouseLeave} maxHeight={isTablet ? "80px" : "300px"} onClick={redirectToBlog} color={"primary.main"} @@ -46,6 +52,7 @@ export default function Blog({ backgroundColor: "#FBFCFA", boxShadow: "3px 3px 10px rgba(214, 208, 174,0.7)", borderRadius: "5px", + cursor: "pointer", }} > diff --git a/src/app/home/home.css b/src/app/home/home.css index 71c162d..b6c0afd 100644 --- a/src/app/home/home.css +++ b/src/app/home/home.css @@ -64,4 +64,18 @@ .mobile-image{ display: none!important; } +} + +.chip-popup { + transition: opacity 0.3s ease, transform 0.3s ease; +} + +.fade-in { + opacity: 1; + transform: scale(1); +} + +.fade-out { + opacity: 0; + transform: scale(0.95); } \ No newline at end of file diff --git a/src/hooks/useCursor.tsx b/src/hooks/useCursor.tsx new file mode 100644 index 0000000..2dd9e08 --- /dev/null +++ b/src/hooks/useCursor.tsx @@ -0,0 +1,45 @@ +// cursor.tsx +import { useState, useEffect } from "react"; + +export interface CursorData { + visible: boolean; + x: number; + y: number; + name: string; + value: string; +} + +export const useCursor = () => { + const [cursorData, setCursorData] = useState({ + visible: false, + x: 0, + y: 0, + name: "", + value: "", + }); + const [isFadingOut, setIsFadingOut] = useState(false); + + const handleMouseMove = ( + e: React.MouseEvent, + name: string, + value: string, + ) => { + setIsFadingOut(false); + setCursorData({ + visible: true, + x: e.clientX, + y: e.clientY, + name, + value, + }); + }; + + const handleMouseLeave = () => { + setIsFadingOut(true); + setTimeout(() => { + setCursorData({ visible: false, x: 0, y: 0, name: "", value: "" }); + }, 300); + }; + + return { cursorData, handleMouseMove, handleMouseLeave, isFadingOut }; +};