Skip to content

Commit

Permalink
feat: revert css-only solution and dynamically determine height of ov…
Browse files Browse the repository at this point in the history
…erview page squash for desktop
  • Loading branch information
aaronchan32 committed May 30, 2024
1 parent 895c046 commit a8f318c
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 87 deletions.
55 changes: 2 additions & 53 deletions src/app/components/Overview/Expectations/Expectations.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#overview {
.expectations-container {
max-height: 550px;
position: relative;
background-color: $secondary-yellow;
padding: 2rem;
Expand Down Expand Up @@ -29,6 +30,7 @@

h3 {
max-width: 16em;
height: fit-content;
}

.expectations-list {
Expand All @@ -49,58 +51,5 @@
}
}
}

.squash-container {
position: absolute;
width: 100%;
height: 100%;
display: grid;
justify-content: center;
align-items: flex-end;
bottom: calc(60% + 7vw);
left: 55%;

@media (min-width: 500px) {
bottom: calc(18% + 7vw);
left: 30%;
}

@media (min-width: 760px) {
transform: rotate(0deg);
right: 0;
left: 0;
bottom: -10%;
}

@media (min-width: 1250px) {
bottom: 0;
}

.squash-image-wrapper {
transform: scaleX(-1) rotate(-80deg);
position: relative;
width: 100%;
// Ideally height is about 100% subtracted by half of expectations list (~8em) and padding (2rem)
@media (min-width: 500px) {
height: calc(100% - 8em - 2rem);
transform: rotate(-90deg);
}

@media (min-width: 760px) {
transform: rotate(0deg);
}

@media (min-width: 1080px) {
height: calc(100% - 6.25em - 2rem);
}
}

.squash {
object-fit: contain;
object-position: bottom;
height: 100%;
width: 100%;
}
}
}
}
23 changes: 11 additions & 12 deletions src/app/components/Overview/Expectations/Expectations.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Image from 'next/image';
import Squash from '@/assets/images/squash.webp';
'use client';

import { useRef } from 'react';
import './Expectations.scss';
import SquashGooglyEyes from '../SquashGoogleEyes/SquashGooglyEyes';
import Squash from '@/components/Overview/Squash/Squash';

type Expectation = {
id: string;
Expand All @@ -11,23 +12,21 @@ type ExpectationsProps = {
expectationsList: Expectation[];
};
export default function Expectations({ expectationsList }: ExpectationsProps) {
const containerRef = useRef<HTMLDivElement>(null);
const listRef = useRef<HTMLUListElement>(null);
const titleRef = useRef<HTMLHeadingElement>(null);
return (
<div className="expectations-container">
<h3>{`Here's what you can expect from UP-Grade:`}</h3>
<ul className="expectations-list">
<div ref={containerRef} className="expectations-container">
<h3 ref={titleRef}>{`Here's what you can expect from UP-Grade:`}</h3>
<ul ref={listRef} className="expectations-list">
{expectationsList.map(expectation => (
<li key={expectation.id}>
<span className="arrow"></span>
<span>{expectation.text}</span>
</li>
))}
</ul>
<div className="squash-container">
<div className="squash-image-wrapper">
<Image className="squash" src={Squash} alt="Squash" />
<SquashGooglyEyes />
</div>
</div>
<Squash expectationRefs={{ containerRef, listRef, titleRef }} />
</div>
);
}
71 changes: 71 additions & 0 deletions src/app/components/Overview/Squash/Squash.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
.squash-container {
position: absolute;
width: 100%;
height: 100%;
display: grid;
justify-content: center;
align-items: flex-end;
bottom: calc(60% + 7vw);
left: 55%;

@media (min-width: 500px) {
bottom: calc(18% + 7vw);
left: 40%;
}

@media (min-width: 760px) {
transform: rotate(0deg);
right: 0;
left: 0;
bottom: -10%;
}

@media (min-width: 1250px) {
bottom: 0;
}

.squash-image-wrapper {
transform: scaleX(-1) rotate(-80deg);
position: relative;
width: 100%;
// Ideally height is about 100% subtracted by half of expectations list (~8em) and padding (2rem)
@media (min-width: 500px) {
width: min(90%, 520px);
transform: rotate(-90deg);
}

@media (min-width: 760px) {
width: auto;
transform: rotate(0deg);
}

@media (min-width: $tablet-breakpoint) {
opacity: 0;
}

&.pop-up {
opacity: 1;
animation: PopUp 0.2s ease-in-out forwards;
}

@keyframes PopUp {
0% {
transform: scale(0);
}

80% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
}

.squash {
object-fit: contain;
object-position: bottom;
height: 100%;
width: 100%;
}
}
39 changes: 39 additions & 0 deletions src/app/components/Overview/Squash/Squash.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client';

import Image from 'next/image';
import SquashGooglyEyes from '../SquashGooglyEyes/SquashGooglyEyes';
import SquashImage from '@/assets/images/squash.webp';
import './Squash.scss';
import { RefObject, useRef } from 'react';
import { useHandleSquashSizing } from './hooks/useHandleSquashSizing';

type SquashProps = {
expectationRefs: {
containerRef: RefObject<HTMLDivElement>;
listRef: RefObject<HTMLUListElement>;
titleRef: RefObject<HTMLHeadingElement>;
};
};

export default function Squash({ expectationRefs }: SquashProps) {
const { containerRef, listRef, titleRef } = expectationRefs;
const squashContainerRef = useRef<HTMLDivElement>(null);
const squashWrapperRef = useRef<HTMLDivElement>(null);

useHandleSquashSizing({
containerRef,
listRef,
titleRef,
squashContainerRef,
squashWrapperRef
});

return (
<div ref={squashContainerRef} className="squash-container">
<div ref={squashWrapperRef} className="squash-image-wrapper">
<Image className="squash" src={SquashImage} alt="Squash" priority />
<SquashGooglyEyes />
</div>
</div>
);
}
74 changes: 74 additions & 0 deletions src/app/components/Overview/Squash/hooks/useHandleSquashSizing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { RefObject, useEffect } from 'react';

// Threshold for space under expectation list to determine if squash should be aligned to the left
const SPACE_THRESHOLD = 130;
// The smaller end of the squash is about 60% of its height
const SQUASH_SMALLER_END_RATIO = 0.67; // 309 / 465

const TABLET_BREAKPOINT = 1000;

type UseHandleSquashSizingProps = {
containerRef: RefObject<HTMLDivElement>;
listRef: RefObject<HTMLUListElement>;
titleRef: RefObject<HTMLHeadingElement>;
squashContainerRef: RefObject<HTMLDivElement>;
squashWrapperRef: RefObject<HTMLDivElement>;
};

export const useHandleSquashSizing = ({
containerRef,
listRef,
titleRef,
squashContainerRef,
squashWrapperRef
}: UseHandleSquashSizingProps) => {
useEffect(() => {
const container = containerRef.current;
const squashContainer = squashContainerRef.current;
const squashWrapper = squashWrapperRef.current;
const title = titleRef.current;
const listRect = listRef.current?.getBoundingClientRect();

if (!container || !title || !listRect || !squashContainer || !squashWrapper)
return;

const handleSquashSizing = () => {
if (window.innerWidth < TABLET_BREAKPOINT) {
// Reset styles potentially set by logic below
squashContainer.style.justifyContent = '';
squashWrapper.style.height = '';
squashWrapper.classList.remove('pop-up');
} else {
const containerRect = container.getBoundingClientRect();
const containerPadding = parseInt(
getComputedStyle(container).paddingTop
);
const spaceUnderList = containerRect.height - listRect.height;
console.log({ spaceUnderList });
const spaceUnderTitle =
containerRect.height - title.getBoundingClientRect().height;

// If there's too little space under list, make the squash aligned to the left
if (spaceUnderList < SPACE_THRESHOLD) {
squashContainer.style.justifyContent = 'flex-start';
squashWrapper.style.height = `${spaceUnderTitle / 1.5}px`;
} else {
const squashHeight =
spaceUnderList +
listRect.height * (1 - SQUASH_SMALLER_END_RATIO) -
containerPadding;
squashWrapper.style.height = `${squashHeight}px`;
}
squashWrapper.classList.add('pop-up');
}
};

handleSquashSizing();

window.addEventListener('resize', handleSquashSizing);

return () => {
window.removeEventListener('resize', handleSquashSizing);
};
}, [containerRef, listRef, squashContainerRef, squashWrapperRef, titleRef]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@
}

.googly-eyes {
&.blink {
animation: Blink 0.18s forwards;
}

@keyframes Blink {
0% {
transform: scaleY(1);
}
50% {
transform: scaleY(0.1);
}
100% {
transform: scaleY(1);
}
}
transform: scale(0.3);

@media (min-width: 380px) {
Expand All @@ -19,19 +34,19 @@
}

@media (min-width: 760px) {
transform: scale(0.7);
transform: scale(0.65);
}

@media (min-width: 1250px) {
transform: scale(0.85);
transform: scale(0.8);
}

@media (min-width: 1440px) {
transform: scale(1);
transform: scale(0.95);
}

@media (min-width: 1750px) {
transform: scale(1.2);
transform: scale(1.1);
}
}

Expand Down Expand Up @@ -63,7 +78,7 @@

@media (min-width: 760px) {
top: auto;
bottom: 30%;
bottom: 28%;
right: 9%;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default function SquashGooglyEyes() {
<div className='googly-eyes-container'>
<svg ref={eye1Ref} className='googly-eyes' id="googly-eye1" width="63" height="63" viewBox="0 0 63 63" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="outer-circle1" filter="url(#filter0_d_2381_2875)">
<circle cx="31.2339" cy="28.6925" r="28.2323" fill="white"></circle>
<circle cx="31.2339" cy="28.6925" r="28.2323" fill="white"></circle>
</g>
<g ref={pupil1Ref} id="pupil1">
<circle cx="30.6305" cy="28.6305" r="18.6305" fill="#212121"></circle>
Expand Down
Loading

0 comments on commit a8f318c

Please sign in to comment.