diff --git a/package.json b/package.json index a7eaa72..cfe651e 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@tanstack/react-router": "^1.34.9", "@tanstack/zod-form-adapter": "^0.20.3", "axios": "^1.7.2", + "framer-motion": "^11.2.11", "lucide-react": "^0.383.0", "moment": "^2.30.1", "react": "^18.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fa843bb..67e7e61 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ importers: axios: specifier: ^1.7.2 version: 1.7.2 + framer-motion: + specifier: ^11.2.11 + version: 11.2.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) lucide-react: specifier: ^0.383.0 version: 0.383.0(react@18.3.1) @@ -1284,6 +1287,20 @@ packages: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} + framer-motion@11.2.11: + resolution: {integrity: sha512-n+ozoEzgJu/2h9NoQMokF+CwNqIRVyuRC4RwMPwklfrrTjbVV32k9uBIgqYAwn7Jfpt5LuDVCtT57MWz1FbaLw==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1891,6 +1908,9 @@ packages: tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + tsutils@3.21.0: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -3331,6 +3351,13 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 + framer-motion@11.2.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + tslib: 2.6.3 + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + fs.realpath@1.0.0: {} fsevents@2.3.2: @@ -3912,6 +3939,8 @@ snapshots: tslib@1.14.1: {} + tslib@2.6.3: {} + tsutils@3.21.0(typescript@5.4.5): dependencies: tslib: 1.14.1 diff --git a/src/components/HeaderAnimate.tsx b/src/components/HeaderAnimate.tsx new file mode 100644 index 0000000..3a87f4f --- /dev/null +++ b/src/components/HeaderAnimate.tsx @@ -0,0 +1,218 @@ +import { styled } from '@/stitches.config'; +import { setLocalStorage } from '@/utils/LocalStorage'; +import { useKindeAuth } from '@kinde-oss/kinde-auth-react'; +import { useNavigate } from '@tanstack/react-router'; +import { motion, useMotionValueEvent, useScroll } from 'framer-motion'; +import { Globe, MapPin, Search } from 'lucide-react'; +import { useEffect, useRef, useState } from 'react'; + +import { AirBnbIcon, HumBurgerIcon } from '../assets'; +import { useOutsideClick } from '../hooks'; +import { Button } from './Button'; +import { Row } from './Common'; +import { Divider } from './Divider'; +import UserMenu from './UserMenu'; + +const locations = [ + 'Banglore', + 'London', + 'Paris', + 'New York', + 'San Francisco', + 'Tokyo', +]; + +function HeaderAnimate() { + const navigate = useNavigate(); + const { getToken, isAuthenticated, isLoading, login, user } = useKindeAuth(); + const [showUserMenu, setShowUserMenu] = useState(false); + const menuRef = useRef(null); + useOutsideClick(menuRef, () => setShowUserMenu(false)); + + const [selectLocation, setSelectLocation] = + useState<(typeof locations)[number]>(''); + const [showLocationOtions, setShowLocationOtions] = useState(false); + + // console.log(user && getPermissions().permissions); + + useEffect(() => { + if (!isAuthenticated) { + localStorage.removeItem('access_token'); + localStorage.removeItem('user'); + return; + } + getToken().then((token) => { + if (token) { + setLocalStorage('access_token', token); + setLocalStorage('user', user); + } + }); + }, [getToken, isAuthenticated, user]); + + const handleSwitchToHosting = () => { + navigate({ to: '/hosting' }); + }; + + const [isHidden, setIsHidden] = useState(false); + const { scrollY } = useScroll(); + const lastRef = useRef(0); + + useMotionValueEvent(scrollY, 'change', (y) => { + const difference = y - lastRef.current; + if (Math.abs(difference) > 50) { + setIsHidden(difference > 0); + lastRef.current = y; + } + }); + + return ( + setIsHidden(false)} + transition={{ duration: 0.3 }} + whileHover="visible" + > + + navigate({ to: '/' })} + style={{ cursor: 'pointer' }} + > + + + + {showLocationOtions && ( +
+ {locations.map((location) => ( + + + + + ))} +
+ )} + + + + + + + + + + + {isAuthenticated && !isLoading && user && ( + + )} + {showUserMenu && } + {!user && !isLoading && ( + + )} + +
+
+ ); +} + +export default HeaderAnimate; + +const HeaderWrapper = styled('div', { + alignItems: 'center', + display: 'flex', + justifyContent: 'space-between', + margin: '0rem 2rem', +}); +const RoundIcon = styled('span', { + alignItems: 'center', + backgroundColor: 'black', + borderRadius: '100%', + color: 'white', + cursor: 'pointer', + display: 'flex', + fontSize: '10px', + fontWeight: '500', + height: '16px', + justifyContent: 'center', + padding: '0.5rem', + width: '16px', +}); + +const GroupWrapper = styled('span', { + alignItems: 'center', + display: 'inline-flex', + gap: '1rem', + justifyContent: 'center', + position: 'relative', +}); diff --git a/src/components/StickyHeader.tsx b/src/components/StickyHeader.tsx index 057607e..260326c 100644 --- a/src/components/StickyHeader.tsx +++ b/src/components/StickyHeader.tsx @@ -1,7 +1,7 @@ -import { styled } from "@stitches/react"; +import { styled } from '@stitches/react'; -import CategoryActionBar from "./CategoryActionBar"; -import Header from "./Header"; +import CategoryActionBar from './CategoryActionBar'; +import Header from './Header'; function StickyHeader() { return ( @@ -14,19 +14,19 @@ function StickyHeader() { } export default StickyHeader; -const StickyHeaderWrapper = styled("div", { - backgroundColor: "white", - paddingTop: "1rem", - position: "fixed", +const StickyHeaderWrapper = styled('div', { + backgroundColor: 'white', + paddingTop: '1rem', + position: 'fixed', top: 0, - width: "100%", - zIndex: "9", + width: '100%', + zIndex: '9', }); -const Line = styled("span", { - backgroundColor: "#eee", - display: "flex", - height: "1px", - margin: "1rem", - width: "100%", +const Line = styled('span', { + backgroundColor: '#eee', + display: 'flex', + height: '1px', + margin: '1rem', + width: '100%', }); diff --git a/src/pages/Room/index.tsx b/src/pages/Room/index.tsx index ee0f2d4..610736a 100644 --- a/src/pages/Room/index.tsx +++ b/src/pages/Room/index.tsx @@ -1,5 +1,5 @@ import { Column, Divider, Row } from '@/components'; -import Header from '@/components/Header'; +import HeaderAnimate from '@/components/HeaderAnimate'; import { styled } from '@/stitches.config'; import { useQuery } from '@tanstack/react-query'; import { useParams } from '@tanstack/react-router'; @@ -43,8 +43,11 @@ function RoomPage() { return ( -
- + + {/* RoomPage {roomId} */} {room.name}