Skip to content

Commit

Permalink
Merge pull request #29 from jchojna/add-intro-fixes
Browse files Browse the repository at this point in the history
Add intro fixes
  • Loading branch information
jchojna authored Apr 24, 2024
2 parents 2430d34 + d531a84 commit a4a627b
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 48 deletions.
10 changes: 7 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ function App() {
const [isMenuMode, setMenuMode] = useState<boolean>(true);
const [isSmoothScroll, setSmoothScroll] = useState<boolean>(false);
const [indicatorRef, setIndicatorRef] = useState<HTMLDivElement | null>(null);
const [isIntroDone, setIntroDone] = useState<boolean>(false);
const currentViewHook = useState<number>(0);

const sectionsRef = useRef<HTMLDivElement | null>(null);
const isMobile = useMediaQuery({ query: '(max-width: 1200px)' });
const sectionsClass = clsx({
Expand All @@ -49,7 +49,11 @@ function App() {
<QueryClientProvider client={queryClient}>
<CurrentViewContext.Provider value={currentViewHook}>
<div className={classes.app}>
<Intro indicator={indicatorRef} />
<Intro
indicator={indicatorRef}
isIntroDone={isIntroDone}
setIntroDone={() => setIntroDone(true)}
/>
{isMobile ? (
<MobileHeader
isMenuMode={isMenuMode}
Expand All @@ -68,7 +72,7 @@ function App() {
<div ref={sectionsRef} className={sectionsClass}>
<About />
<Resume />
<Projects />
{isIntroDone && <Projects />}
<Contact />
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Header.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
bottom: 0;
left: 0;
min-height: 100vh;
overflow: auto;
overflow: hidden;
opacity: 0;
padding: $mobile-menu-offset-top 0;
pointer-events: none;
Expand Down
3 changes: 0 additions & 3 deletions src/components/Menu.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,6 @@
left: 0;
position: absolute;
top: 0;
transition: background-color $time-menu-indicator, left $time-menu-indicator,
top $time-menu-indicator $menu-button-time,
width $time-menu-indicator 0.4s ease-out;
width: 20px;
z-index: 9999;

Expand Down
52 changes: 21 additions & 31 deletions src/components/Menu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import clsx from 'clsx';
import { useContext, useEffect, useRef, useState } from 'react';
import { useContext, useEffect, useRef } from 'react';

import menuItems from '../content/menu.json';
import { getCurrentSectionIndex } from '../utils/utils';
import {
getCurrentSectionIndex,
handleIndicator,
updateIndicatorStyle,
} from '../utils/utils';
import CurrentViewContext from '../views/CurrentViewContext';
import MenuButton from './MenuButton';

Expand All @@ -23,14 +27,10 @@ const Menu = ({
sectionsRef,
setIndicatorRef,
}: MenuProps) => {
const [hoveredItem, setHoveredItem] = useState<number | null>(0);

const [currentSectionIndex, setCurrentSectionIndex] =
useContext(CurrentViewContext);

const indicatorRef = useRef<HTMLDivElement>(null);
const menuListRef = useRef<HTMLUListElement>(null);
const hoveredItemName = menuItems.map(({ label }) => label)[hoveredItem || 0];

const handleScroll = () => {
if (!sectionsRef.current) return;
Expand All @@ -53,31 +53,21 @@ const Menu = ({
}
}, []); // eslint-disable-line react-hooks/exhaustive-deps

useEffect(() => {
handleIndicator();
window.addEventListener('resize', handleIndicator);
return () => window.removeEventListener('resize', handleIndicator);
}, []); // eslint-disable-line react-hooks/exhaustive-deps

// handle indicator position
useEffect(() => {
if (!indicatorRef.current) return;
if (!menuListRef.current) return;
const indicator = indicatorRef.current;
if (isMenuMode) {
const { top, height } =
menuListRef.current.children[
hoveredItem !== null ? hoveredItem : currentSectionIndex
].getBoundingClientRect();
indicator.style.top = `${top}px`;
indicator.style.left = `${window.innerWidth / 2 + 20}px`;
indicator.style.height = `${height}px`;
indicator.style.width = `${height}px`;
} else {
const { top } =
menuListRef.current.children[
currentSectionIndex
].getBoundingClientRect();
indicator.style.top = `${top}px`;
indicator.style.left = '0px';
indicator.style.width = '20px';
setHoveredItem(currentSectionIndex);
}
}, [hoveredItem, currentSectionIndex, isMenuMode]);
const { top, height } =
menuListRef.current.children[currentSectionIndex].getBoundingClientRect();
updateIndicatorStyle(indicator, isMenuMode, top, height);
}, [currentSectionIndex, isMenuMode]);

const menuClass = clsx({
[classes.menu]: true,
Expand All @@ -88,11 +78,11 @@ const Menu = ({
<>
<div
ref={indicatorRef}
data-id="indicator"
className={clsx(
classes.indicator,
isMenuMode && classes[hoveredItemName],
isMenuMode && classes.intro,
!isMenuMode && classes[menuItems[currentSectionIndex].label]
classes[menuItems[currentSectionIndex].label]
)}
></div>
<nav className={menuClass}>
Expand All @@ -102,15 +92,15 @@ const Menu = ({
<li
key={index}
className={classes.menuItem}
onMouseEnter={() => setHoveredItem(index)}
onMouseLeave={() => !isMenuMode && setHoveredItem(null)}
onMouseEnter={() => {
isMenuMode && setCurrentSectionIndex(index);
}}
>
<MenuButton
index={index}
label={label}
width={width}
isMenuMode={isMenuMode}
isHovered={hoveredItem === index}
isActive={currentSectionIndex === index}
sectionsRef={sectionsRef}
setMenuMode={setMenuMode}
Expand Down
5 changes: 2 additions & 3 deletions src/components/MenuButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ type MenuButtonProps = {
label: string;
width: number;
isMenuMode: boolean;
isHovered: boolean;
isActive?: boolean;
sectionsRef: React.RefObject<HTMLDivElement>;
setMenuMode: (isMenuMode: boolean) => void;
Expand All @@ -23,7 +22,6 @@ const MenuButton = ({
label,
width,
isMenuMode,
isHovered,
isActive,
setMenuMode,
sectionsRef,
Expand All @@ -32,7 +30,6 @@ const MenuButton = ({
const buttonClass = clsx({
[classes.menuButton]: true,
[classes.intro]: isMenuMode,
[classes.hovered]: isHovered,
[classes[label]]: true,
[classes.active]: isActive,
});
Expand All @@ -53,6 +50,8 @@ const MenuButton = ({
<a
ref={buttonRef}
className={buttonClass}
data-button-active={isActive}
data-menu-mode={isMenuMode}
onClick={() => handleClick(index)}
>
<div className={classes.menuSvg}>
Expand Down
38 changes: 38 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,41 @@ export const getViewLocation = (
? 'next'
: 'prev';
};

export const updateIndicatorStyle = (
indicator: HTMLElement,
isMenuMode: boolean,
top: number,
height: number
) => {
if (isMenuMode) {
indicator.style.top = `${top}px`;
indicator.style.left = `${window.innerWidth / 2 + 20}px`;
indicator.style.height = `${height}px`;
indicator.style.width = `${height}px`;
} else {
indicator.style.top = `${top}px`;
indicator.style.left = '0px';
indicator.style.width = '20px';
}
};

export const handleIndicator = () => {
const indicator = document.querySelector('[data-id="indicator"]');
const activeMenuItem = document.querySelector('[data-button-active="true"]');
if (!indicator || !(indicator instanceof HTMLElement)) return;
if (!activeMenuItem) return;
const isMenuMode = activeMenuItem.getAttribute('data-menu-mode') === 'true';
const { top, height } = activeMenuItem.getBoundingClientRect();

indicator.style.transition = 'none';
updateIndicatorStyle(indicator, isMenuMode, top, height);
setTimeout(() => {
indicator.style.transition = `
background-color 0.6s,
left 0.6s,
top 0.6s 0.2s,
width 0.6s 0.4s ease-out
`;
}, 0);
};
14 changes: 7 additions & 7 deletions src/views/Intro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import classes from './Intro.module.scss';

type IntroProps = {
indicator: HTMLDivElement | null;
isIntroDone: boolean;
setIntroDone: () => void;
};

const Intro = ({ indicator }: IntroProps) => {
const [isIntroVisible, setIntroVisible] = useState<boolean>(true);

const Intro = ({ indicator, isIntroDone, setIntroDone }: IntroProps) => {
const introRef = useRef<HTMLDivElement | null>(null);
const loaderRef = useRef<HTMLDivElement | null>(null);
const endingBeforeRef = useRef<HTMLDivElement | null>(null);
Expand All @@ -31,15 +31,15 @@ const Intro = ({ indicator }: IntroProps) => {
skipButtonRef.current,
indicator
);
setIntroVisible(false);
setIntroDone();
};
runIntro();
}, [indicator]);
}, [indicator, setIntroDone]);

return (
<div
ref={introRef}
className={clsx(classes.intro, isIntroVisible && classes.visible)}
className={clsx(classes.intro, !isIntroDone && classes.visible)}
>
<div
ref={loaderRef}
Expand All @@ -57,7 +57,7 @@ const Intro = ({ indicator }: IntroProps) => {
<button
ref={skipButtonRef}
className={classes.skipButton}
onClick={() => setIntroVisible(false)}
onClick={setIntroDone}
>
Skip Intro
</button>
Expand Down

0 comments on commit a4a627b

Please sign in to comment.