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
8 changes: 8 additions & 0 deletions jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,11 @@ jest.mock('ogl', () => ({
Triangle: jest.fn(),
Mesh: jest.fn(),
}));

global.ResizeObserver = class ResizeObserver {
observe = jest.fn();
unobserve = jest.fn();
disconnect = jest.fn();
};


5 changes: 2 additions & 3 deletions src/components/Button/LinkButton/LinkButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import { useRef } from 'react';

const LinkButton = ({
text,
href,
animationOnHover,
withUnderline,
withArrow,
fontSize,
onClick,
href = undefined,
}: LinkButtonProps) => {
const ref = useRef<HTMLButtonElement>(null);
const { setCursorInsets } = useCursor();
Expand Down Expand Up @@ -52,7 +51,7 @@ const LinkButton = ({
rightIcon={withArrow ? <ArrowIcon /> : undefined}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onClick={() => onClick?.(href)}
onClick={() => href && onClick?.(href)}
justifyItems={'end'}
rowGap={2}
{...(!onClick ? { as: 'a', href } : {})}
Expand Down
3 changes: 1 addition & 2 deletions src/components/Button/LinkButton/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { BoxProps } from '@chakra-ui/react';

export type LinkButtonProps = {
href: string;
text: string;
withUnderline?: boolean;
withArrow?: boolean;
animationOnHover?: boolean;
href?: string;
fontSize?: BoxProps['fontSize'];
onClick?: (target: string) => void;
};
31 changes: 28 additions & 3 deletions src/components/Cursor/FollowCursor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,40 @@ const FollowCursor = () => {
const shouldHide = hasInsets && (insets.width === 0 || insets.height === 0);

useEffect(() => {
let mouseTimeout: ReturnType<typeof setTimeout> | null = null;

const enableIframePointerEvents = () => {
document.body.classList.remove('disable-iframe-pointer-events');
};

const disableIframePointerEvents = () => {
document.body.classList.add('disable-iframe-pointer-events');
if (mouseTimeout) clearTimeout(mouseTimeout);
mouseTimeout = setTimeout(enableIframePointerEvents, 150);
};

const handleMouseMove = (e: MouseEvent) => {
dotTargetX.set(e.clientX);
dotTargetY.set(e.clientY);
ringTargetX.set(e.clientX);
ringTargetY.set(e.clientY);

disableIframePointerEvents();
};

const handleMouseDown = () => {
enableIframePointerEvents();
};

window.addEventListener('mousemove', handleMouseMove, { passive: true });
return () => window.removeEventListener('mousemove', handleMouseMove);
window.addEventListener('mousedown', handleMouseDown, { passive: true });

return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mousedown', handleMouseDown);
if (mouseTimeout) clearTimeout(mouseTimeout);
enableIframePointerEvents();
};
}, [dotTargetX, dotTargetY, ringTargetX, ringTargetY]);

const ringSize = shouldHide ? 0 : isHovering ? 48 : 36;
Expand All @@ -72,7 +97,7 @@ const FollowCursor = () => {
borderRadius: '50%',
backgroundColor: '#ffffff',
mixBlendMode: 'difference',
zIndex: 99999,
zIndex: 2147483647,
pointerEvents: 'none',
x: dotX,
y: dotY,
Expand Down Expand Up @@ -105,7 +130,7 @@ const FollowCursor = () => {
position: 'fixed',
left: 0,
top: 0,
zIndex: 99998,
zIndex: 2147483646,
pointerEvents: 'none',
x: ringX,
y: ringY,
Expand Down
43 changes: 43 additions & 0 deletions src/components/ResumeAudioPlayer/ResumeAudioPlayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Box } from '@chakra-ui/react';

export interface ResumeAudioPlayerProps {
audioUrl: string;
title?: string;
subtitle?: string;
fallbackDuration?: string;
}

const ResumeAudioPlayer = ({
audioUrl,
title = 'Audio Walkthrough',
}: ResumeAudioPlayerProps) => {
const isGDrive = audioUrl.includes('drive.google.com');
const embedSrc = isGDrive
? audioUrl.replace(/\/view.*/, '/preview')
: audioUrl;

return (
<Box
width="100%"
borderRadius="8px"
border="1px solid rgba(255, 255, 255, 0.12)"
boxShadow="0 4px 20px 0 rgba(0, 0, 0, 0.4)"
bg="rgba(18, 18, 22, 0.85)"
height={'50px'}
overflow="hidden"
>
<iframe
src={embedSrc}
title={title}
style={{
width: '100%',
transform: 'scaleY(0.5)',
transformOrigin: 'top left',
zIndex: 1,
}}
/>
</Box>
);
};

export default ResumeAudioPlayer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import ResumeAudioPlayer from '../ResumeAudioPlayer';

describe('ResumeAudioPlayer', () => {
it('should render audio iframe with title attribute for direct audio link', () => {
render(
<ResumeAudioPlayer
audioUrl="/audio/test.mp3"
title="Test Title"
/>,
);

const iframe = screen.getByTitle('Test Title');
expect(iframe).toBeInTheDocument();
expect(iframe).toHaveAttribute('src', '/audio/test.mp3');
});

it('should render Google Drive iframe with preview URL when audioUrl is a GDrive link', () => {
render(
<ResumeAudioPlayer
audioUrl="https://drive.google.com/file/d/1C3Vq5pMbjbdHHq56d8gWpblUjv9RYln-/view?usp=drive_link"
title="GDrive Audio"
/>,
);

const iframe = screen.getByTitle('GDrive Audio');
expect(iframe).toBeInTheDocument();
expect(iframe).toHaveAttribute(
'src',
'https://drive.google.com/file/d/1C3Vq5pMbjbdHHq56d8gWpblUjv9RYln-/preview',
);
});
});
2 changes: 2 additions & 0 deletions src/components/ResumeAudioPlayer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as ResumeAudioPlayer } from './ResumeAudioPlayer';
export type { ResumeAudioPlayerProps } from './ResumeAudioPlayer';
10 changes: 5 additions & 5 deletions src/components/animateModal/AnimatedModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,16 @@ export const ModalBody = ({
backdropFilter: 'blur(0px)',
}}
className={
'fixed [perspective:800px] [transform-style:preserve-3d] inset-0 h-full w-full flex items-center justify-center z-100 ' +
'fixed [perspective:800px] [transform-style:preserve-3d] inset-0 h-full w-full flex items-center justify-center z-[9000] ' +
className
}
>
<Overlay />
<motion.div
ref={modalRef}
className={
'min-h-[50%] max-h-[90%] max-w-[60%] bg-white dark:bg-neutral-950 border border-transparent dark:border-neutral-800 md:rounded-2xl relative z-10 flex flex-col flex-1 overflow-hidden'
}
className={`min-h-[50%] max-h-[95%] ${
className ? className : 'max-w-[60%]'
} bg-white dark:bg-neutral-950 border border-transparent dark:border-neutral-800 md:rounded-2xl relative z-[9001] flex flex-col flex-1 overflow-hidden`}
initial={{
opacity: 0,
scale: 0.5,
Expand Down Expand Up @@ -176,7 +176,7 @@ const Overlay = ({ className }: { className?: string }) => {
opacity: 0,
backdropFilter: 'blur(0px)',
}}
className={`fixed inset-0 h-full w-full bg-black bg-opacity-50 z-100 ${className}`}
className={`fixed inset-0 h-full w-full bg-black bg-opacity-50 z-[9001] ${className}`}
></motion.div>
);
};
Expand Down
18 changes: 11 additions & 7 deletions src/components/animateModal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ const AnimatedModal = ({
triggerComponent,
children,
footer,
containerClassName,
}: {
title: string;
triggerComponent: React.ReactNode;
children: React.ReactNode;
footer: React.ReactNode;
containerClassName?: string;
}) => {
return (
<Box className="flex items-center justify-center">
Expand All @@ -26,13 +28,15 @@ const AnimatedModal = ({
</ModalTrigger>
<ModalBody>
<ModalContent>
<Heading
fontSize="xl"
className="text-center text-white"
marginBottom={'4'}
>
{title}
</Heading>
{title && (
<Heading
fontSize="xl"
className="text-center text-white"
marginBottom={'4'}
>
{title}
</Heading>
)}
{children}
</ModalContent>
<ModalFooter>{footer}</ModalFooter>
Expand Down
2 changes: 2 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ export * from './GlassBox';
export * from './BorderGlow';
export * from './Orb';
export * from './WebsiteLoader';
export * from './ResumeAudioPlayer';

2 changes: 2 additions & 0 deletions src/data/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export { PROJECT_DATA } from './Projects';
export { WORK_DATA } from './Work';
export { CONTACT } from './contact';
export { RESUME_DATA } from './resume';
export * from './types';

22 changes: 22 additions & 0 deletions src/data/resume.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface ResumeData {
gdriveViewUrl: string;
gdriveDownloadUrl: string;
audioUrl: string;
audioDuration: string;
highlights: string[];
}

export const RESUME_DATA: ResumeData = {
gdriveViewUrl:
'https://drive.google.com/file/d/1wSTgBKD-me8VoJEKuQ71INGCiCrZK_pY/preview',
gdriveDownloadUrl:
'https://drive.google.com/uc?export=download&id=1BojE5ecoNn8y6zFyJphQ5Td59OISDljm',
audioUrl:
'https://drive.google.com/file/d/1C3Vq5pMbjbdHHq56d8gWpblUjv9RYln-/preview',
audioDuration: '9:31',
highlights: [
'5+ years of experience in Full-Stack & Mobile Development (React, React Native, TypeScript)',
'Key achievements at Raja Software Labs',
'Specialized in Performance Optimization, Custom UI Components, and State Architecture',
],
};
6 changes: 6 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,9 @@ body,
background-color: rgba(193, 129, 193, 0.576);
color: black; /* Optional: set text color within selection */
}

/* Allow custom cursor to track smoothly over iframes without getting stuck at boundaries */
body.disable-iframe-pointer-events iframe {
pointer-events: none !important;
}

10 changes: 10 additions & 0 deletions src/localization/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,19 @@
"work": "Work",
"projects": "Projects",
"skills": "Skills",
"resume": "Resume",
"articles": "Articles",
"contact": "Contact"
},
"resume": {
"title": "Resume",
"subtitle": "Interactive Resume & Audio Walkthrough",
"audioTitle": "Audio Walkthrough",
"audioSubtitle": "Listen to a quick audio summary of my professional journey",
"pdfTitle": "Resume Document",
"openInDrive": "View in Google Drive",
"downloadPdf": "Download PDF"
},
"about": {
"quoteHeading": "Crafting digital experiences that inspire",
"quoteSubheading": "Let your imagination run wild.",
Expand Down
26 changes: 25 additions & 1 deletion src/screens/common/NavigationBar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Button, HStack, Img } from '@chakra-ui/react';
import { Box, Button, HStack, Img, Text } from '@chakra-ui/react';
import { AnimatedModal, LinkButton, useCursor, GlassBox } from '@components';
import AmitRaikwarLogo from '@assets/images/AmitRaikwarLogo.png';
import { SearchIcon } from '@assets';
Expand All @@ -8,6 +8,7 @@ import { Link, useLocation, useNavigate } from 'react-router-dom';
import { useMoveToTop } from '@hooks';
import { BASE_URL_ROUTE } from '@router';
import PingTest from './PingTest';
import Resume from '../mainFlow/contents/Resume';

const NavigationLink = [
{
Expand Down Expand Up @@ -240,6 +241,29 @@ const NavigationBar = () => {
{t(ArticleLink.name)}
</Button>
</Box>
<Text
color={'white'}
fontSize={{ base: 'xs', sm: 'sm', md: 'lg' }}
display={{
base: 'none',
md: 'block',
}}
>
{'|'}
</Text>
<AnimatedModal
triggerComponent={
<LinkButton
text={t('navigation.resume')}
fontSize={{ base: 'xs', sm: 'sm', md: 'lg' }}
/>
}
title={t('resume.title')}
containerClassName="w-[92vw] max-w-[1100px]"
footer={<Box></Box>}
>
<Resume />
</AnimatedModal>
</HStack>
)}

Expand Down
4 changes: 2 additions & 2 deletions src/screens/common/SocialNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const SocialNavigation = () => {
transform="translateY(-50%)"
right={14}
rowGap={6}
zIndex={1000}
zIndex={500}
display={{ base: 'none', lg: 'flex' }}
>
<VStack
Expand Down Expand Up @@ -166,7 +166,7 @@ const SocialNavigation = () => {
position="fixed"
bottom={{ base: '20px', md: '30px' }}
right={{ base: '20px', md: '30px' }}
zIndex={1100}
zIndex={500}
display={{ base: 'block', lg: 'none' }}
>
<IconButton
Expand Down
2 changes: 2 additions & 0 deletions src/screens/mainFlow/contents/Contents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ const Contents = () => {
);
};



export default Contents;
Loading
Loading