Skip to content

Refactor(frontend): Navbar and animations #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Feb 5, 2025
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
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"clsx": "^2.1.1",
"graphql": "^16.9.0",
"graphql-request": "^7.1.0",
"motion": "^12.0.11",
"next": "^15.1.4",
"overlayscrollbars": "^2.10.1",
"overlayscrollbars-react": "^0.5.6",
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/home/components/TrustedBy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ const PartnersCarousel: React.FC<IPartnersCarousel> = ({ partners }) => (
<div
key={name}
className={clsx(
"relative mx-2 inline-block h-16 w-16 rounded-full bg-white lg:mx-10",
"hover:cursor-pointer",
"relative mx-2 inline-block h-16 w-16 rounded-full bg-white",
"hover:cursor-pointer lg:mx-10",
)}
>
<Image
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react";

import clsx from "clsx";
import { Urbanist } from "next/font/google";

import Footer from "@/components/Footer";
Expand All @@ -25,7 +26,7 @@ export default async function RootLayout({
return (
<html lang="en" data-overlayscrollbars-initialize>
<OverlayScrollbarBody className="bg-background-1 antialiased">
<main className={urbanist.className}>
<main className={clsx(urbanist.className)}>
<Navbar {...{ navbarData }} />
{children}
<Footer />
Expand Down
13 changes: 9 additions & 4 deletions frontend/src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@ const Footer: React.FC = async () => {
}));
return (
<div>
<div className={"bg-primary-purple py-16"}>
<div className="flex flex-col gap-12 px-6">
<div className={"bg-background-dark py-16 md:px-16 xl:px-32"}>
<div
className={clsx(
"grid grid-flow-col grid-cols-2 grid-rows-2 gap-12 px-6",
"lg:grid-cols-4 lg:grid-rows-1",
)}
>
{sections.map(({ title, links }) => (
<div key={title} className="flex flex-col gap-4">
<h2 className="text-background-2">{title}</h2>
<h2 className="text-primary-purple">{title}</h2>
{links.map(({ name, url }) => (
<CustomLink
className={clsx(hoverScaleUp, "w-max")}
Expand All @@ -38,7 +43,7 @@ const Footer: React.FC = async () => {
</div>
))}
</div>
<hr className="mx-6 mb-6 mt-16 h-0.5 border-t-0 bg-secondary-purple" />
<hr className="mx-6 mb-6 mt-16 h-0.5 border-t-0 bg-primary-purple" />
<div className="flex items-center justify-center gap-8">
{socials.map(({ name, icon_white: icon, url }) => (
<CustomLink className={hoverScaleUp} key={name} href={url}>
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/components/IntegrateSection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ const IntegrateSection: React.FC = async () => {
<p className="text-base text-secondary-text lg:mb-4 lg:text-lg">
{integrateData.description}
</p>
<AppsDropdownContent appsSection={integrateData.appsSection} />
<AppsDropdownContent
appsSection={integrateData.appsSection}
className="pt-8 lg:pt-16"
/>
<LearnMore
background={integrateData.getInTouchSection.background}
title={integrateData.header}
button={integrateData.arrowLink}
className="!mt-16 lg:!mt-4"
className="!mt-12 lg:!mt-16"
/>
<ExternalLink
className="mt-12 flex-wrap justify-center text-center lg:mt-16"
Expand Down
56 changes: 21 additions & 35 deletions frontend/src/components/Navbar/AppsDropdownContent/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,70 +3,56 @@ import Image from "next/image";

import CustomLink from "@/components/CustomLink";
import { Solution } from "@/queries/navbar";
import { hoverEffect } from "@/styles";

const cardBaseStyle = clsx(
"bg-background-2 rounded-2xl border border-stroke text-wrap",
"p-4 flex gap-4 h-full lg:items-start",
);
const headerTextStyle = clsx("text-primary-purple font-bold text-base");
const descriptionTextStyle = clsx(
"text-secondary-text text-base leading-tight",
);

interface CardProps {
interface ICard {
solution: Solution;
variant: "large" | "medium" | "small";
onClick?: () => void;
className?: string;
}

const Card: React.FC<CardProps> = ({ solution, variant, className }) => {
const Card: React.FC<ICard> = ({ solution, variant, onClick, className }) => {
return (
<CustomLink
key={solution?.solution_name}
href={solution?.url}
className={clsx(
cardBaseStyle,
hoverEffect,
"flex-row",
"w-full",
className,
"flex h-full w-full transform flex-row gap-4 text-wrap rounded-2xl",
"border border-stroke bg-background-2 p-4 transition duration-100",
"hover:scale-[1.01] lg:items-start",
{
"xl:flex-col xl:pb-8": variant === "large",
"xl:flex-row": variant === "medium" || variant === "small",
"xl:w-[380px]": true,
"lg:flex-col": variant === "large",
"lg:flex-row": variant === "medium" || variant === "small",
},
className,
)}
{...{ onClick }}
>
<Image
src={solution?.logo_svg?.url}
alt={solution?.solution_name}
width={64}
height={64}
/>
<div>
<h2 className={headerTextStyle}>{solution?.solution_name}</h2>
<div className="space-y-2">
<h2 className="text-base font-medium text-primary-purple">
{solution?.solution_name}
</h2>

<h3
className={clsx(
headerTextStyle,
"mt-1 leading-tight text-primary-text",
{
"font-normal": variant === "small",
"xl:text-xl": variant === "large",
"xl:text-lg": variant === "medium",
"xl:text-base": variant === "small",
},
)}
className={clsx("text-base font-medium text-primary-text", {
"md:text-lg lg:text-xl": variant === "large",
"md:text-lg": variant === "medium",
"md:text-lg lg:text-base": variant === "small",
})}
>
{solution?.header_title}
</h3>

{solution?.header_description && (
<p
className={clsx(descriptionTextStyle, "mt-2", {
className={clsx("mt-2 text-base text-secondary-text", {
hidden: true,
"lg:block": variant !== "small",
"md:block": variant !== "small",
})}
>
{solution?.header_description}
Expand Down
75 changes: 35 additions & 40 deletions frontend/src/components/Navbar/AppsDropdownContent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,51 @@ import Card from "./Card";

interface AppsDropdownContentProps {
appsSection: AppsSection;
closeFn?: () => void;
className?: string;
}

const AppsDropdownContent: React.FC<AppsDropdownContentProps> = ({
appsSection,
}) => {
const columnOne = appsSection?.solutions.slice(0, 1);
const columnTwo = appsSection?.solutions.slice(1, 3);
const columnThree = appsSection?.solutions.slice(3, 7);

return (
closeFn,
className,
}) => (
<div className={clsx(className, "mx-auto lg:max-w-[1172px]")}>
<div
className={clsx(
"mt-4 grid w-full gap-3 py-2 xl:mt-0 xl:w-[1172px] xl:gap-4 xl:py-12",
"mx-auto grid-cols-1 bg-background-2 xl:grid-cols-3",
"grid w-full grid-cols-1 gap-3 bg-background-2 lg:grid-flow-col",
"lg:grid-cols-3 lg:grid-rows-4 lg:gap-4",
)}
>
<div className="flex flex-col gap-3 xl:gap-4">
{columnOne?.map((solution) => (
<Card
key={solution.solution_name}
solution={solution}
variant="large"
/>
))}
</div>
<div className="flex flex-col gap-3 xl:gap-4">
{columnTwo?.map((solution) => (
<Card
key={solution.solution_name}
solution={solution}
variant="medium"
/>
))}
</div>
<div className="flex flex-col gap-3 xl:gap-4">
{columnThree?.map((solution) => (
<Card
key={solution.solution_name}
solution={solution}
variant="small"
/>
))}
<ExternalLink
url={appsSection?.arrowLink.link.url}
text={appsSection?.arrowLink.text}
className="self-start xl:self-end"
{appsSection?.solutions.map((solution, i) => (
<Card
className={getRowSpan(i)}
key={solution.solution_name}
{...{ solution }}
variant={getVariant(i)}
onClick={closeFn}
/>
</div>
))}
</div>
);
<ExternalLink
className="ml-auto mt-2 w-max"
url={appsSection?.arrowLink.link.url}
text={appsSection?.arrowLink.text}
/>
</div>
);

const getVariant = (index: number): "large" | "medium" | "small" => {
if (index === 0) return "large";
if (index < 3) return "medium";
return "small";
};

const getRowSpan = (
index: number,
): "lg:row-span-4" | "lg:row-span-2" | undefined => {
if (index === 0) return "lg:row-span-4";
if (index < 3) return "lg:row-span-2";
};

export default AppsDropdownContent;
64 changes: 44 additions & 20 deletions frontend/src/components/Navbar/DesktopNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import { useState } from "react";

import clsx from "clsx";
import { motion, AnimatePresence } from "motion/react";
import Image from "next/image";
import Link from "next/link";
import { useLockBodyScroll } from "react-use";
Expand Down Expand Up @@ -51,6 +53,7 @@ const DesktopNavigation: React.FC<DesktopNavigationProps> = ({
className={`${
pathname === `/${navLink.path_name}` ? "font-bold" : ""
}`}
onClick={() => setOpenDropdownIndex(null)}
>
{navLink.title}
</Link>
Expand All @@ -70,30 +73,51 @@ const DesktopNavigation: React.FC<DesktopNavigationProps> = ({
alt="Down Arrow"
width={12}
height={12}
className="ml-2"
className={clsx("ml-2 transition", {
"rotate-180": openDropdownIndex === index,
})}
/>
</button>

{openDropdownIndex === index && navLink.is_dropdown ? (
<div
className="animate-slideInFromTop fixed inset-0 z-40 bg-black bg-opacity-50"
onClick={() => setOpenDropdownIndex(null)}
>
<div
className="relative mt-20 bg-background-2"
onClick={(e) => e.stopPropagation()}
<AnimatePresence>
{openDropdownIndex === index && navLink.is_dropdown ? (
<motion.div
className={clsx(
"fixed inset-0 top-20 z-40 h-[calc(100dvh-5rem)]",
"bg-black/50",
)}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={() => setOpenDropdownIndex(null)}
>
{navLink?.title === "Apps" ? (
<AppsDropdownContent {...{ appsSection }} />
) : null}
{navLink?.title === "Resources" ? (
<ResourcesDropdownContent
{...{ resourceSections, socials }}
/>
) : null}
</div>
</div>
) : null}
<motion.div
className={clsx(
"absolute top-0 max-h-full w-full overflow-y-auto",
"bg-background-2",
)}
initial={{ translateY: "-5%" }}
animate={{ translateY: 0 }}
exit={{ translateY: "-5%" }}
onClick={(e) => e.stopPropagation()}
>
{navLink?.title === "Apps" ? (
<AppsDropdownContent
className="px-6 py-12"
{...{ appsSection }}
closeFn={() => setOpenDropdownIndex(null)}
/>
) : null}
{navLink?.title === "Resources" ? (
<ResourcesDropdownContent
{...{ resourceSections, socials }}
closeFn={() => setOpenDropdownIndex(null)}
/>
) : null}
</motion.div>
</motion.div>
) : null}
</AnimatePresence>
</>
)}
</div>
Expand Down
Loading