Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
yarn run test
yarn run lint
yarn lint-staged
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"add:npmrc": "cp .npmrc.template .npmrc",
"vercel:install": "yarn run add:npmrc && yarn install",
"lint": "eslint .",
"pretty": "prettier --write **/*.{js,jsx,tsx,ts}"
"pretty": "prettier --write **/*.{js,jsx,tsx,ts}",
"prepare": "husky"
},
"dependencies": {
"@headlessui/react": "2.2.9",
Expand Down Expand Up @@ -81,6 +82,7 @@
"autoprefixer": "10.4.21",
"dotenv": "17.2.3",
"eslint": "9.38.0",
"husky": "9.1.7",
"jsdom": "27.0.1",
"lint-staged": "16.2.6",
"postcss": "8.5.6",
Expand Down
17 changes: 8 additions & 9 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { Toaster } from "react-hot-toast";
import { BrowserRouter, Navigate, Route, Routes, useParams, useSearchParams } from "react-router-dom";
import RootDropzone from "./components/RootDropzone";
import { FilesProvider } from "./contexts/Files";
import DownloadView from "./views/DownloadView";
import HomeView from "./views/HomeView";
import NotFoundView from "./views/NotFoundView";

import { Toaster } from 'react-hot-toast';
import { BrowserRouter, Navigate, Route, Routes, useParams, useSearchParams } from 'react-router-dom';
import RootDropzone from './components/RootDropzone';
import { FilesProvider } from './contexts/Files';
import DownloadView from './views/DownloadView';
import HomeView from './views/HomeView';
import NotFoundView from './views/NotFoundView';

function DownloadRedirectWrapper() {
const { sendId } = useParams();
const [searchParams] = useSearchParams();
const code = searchParams.get("code") ?? '';
const code = searchParams.get('code') ?? '';

return <Navigate to={`/d/${sendId}/${code}`} replace />;
}
Expand Down
173 changes: 82 additions & 91 deletions src/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
import { ReactNode, RefObject, useEffect, useRef, useState } from "react";

import Card from "./components/Card";
import Navbar from "./components/Navbar/Navbar";
import { ArrowCircleDown, CaretRight } from "phosphor-react";
import lang from "./assets/lang/en/send.json";
import Privacy from "./assets/images/HeroSectionImages/Privacy.webp";
import Blog from "./assets/images/HeroSectionImages/Blog.webp";
import Pricing from "./assets/images/HeroSectionImages/Pricing.webp";
import PrivacyLaptop from "./assets/images/HeroSectionImages/Privacy.svg";
import BlogLaptop from "./assets/images/HeroSectionImages/Blog.svg";
import PricingLaptop from "./assets/images/HeroSectionImages/Pricing.svg";
import { ReactNode, RefObject, useEffect, useRef, useState } from 'react';

import Card from './components/Card';
import Navbar from './components/Navbar/Navbar';
import { ArrowCircleDown, CaretRight } from 'phosphor-react';
import lang from './assets/lang/en/send.json';
import Privacy from './assets/images/HeroSectionImages/Privacy.webp';
import Blog from './assets/images/HeroSectionImages/Blog.webp';
import Pricing from './assets/images/HeroSectionImages/Pricing.webp';
import PrivacyLaptop from './assets/images/HeroSectionImages/Privacy.svg';
import BlogLaptop from './assets/images/HeroSectionImages/Blog.svg';
import PricingLaptop from './assets/images/HeroSectionImages/Pricing.svg';

interface Item {
text: {
title: string;
description: string;
cta?: string;
ctaLink?: string;
};
image?: string;
background:
| {
backgroundImage: string;
background?: undefined;
}
| {
background: string;
backgroundImage?: undefined;
};
}

const heroSectionTextPaths = [
lang.HeroSection.index,
Expand All @@ -19,59 +38,37 @@ const heroSectionTextPaths = [
lang.HeroSection.pricing,
];

const heroSectionImages = [
`${window.origin}/Drive-1.webp`,
Privacy,
Blog,
Pricing,
];
const heroSectionImagesForLaptop = [
`${window.origin}/Drive-1.webp`,
PrivacyLaptop,
BlogLaptop,
PricingLaptop,
];
const heroSectionImages = [`${window.origin}/Drive-1.webp`, Privacy, Blog, Pricing];
const heroSectionImagesForLaptop = [`${window.origin}/Drive-1.webp`, PrivacyLaptop, BlogLaptop, PricingLaptop];
const backgroundColor = [
{ backgroundImage: `url(${window.origin}/bg.png)` },
{
background: "radial-gradient(50% 50% at 50% 50%, #00A4C8 0%, #161616 100%)",
background: 'radial-gradient(50% 50% at 50% 50%, #00A4C8 0%, #161616 100%)',
},
{
background: "radial-gradient(50% 50% at 50% 50%, #905CFF 0%, #161616 100%)",
background: 'radial-gradient(50% 50% at 50% 50%, #905CFF 0%, #161616 100%)',
},
{
background: "radial-gradient(50% 50% at 50% 50%, #0058DB 0%, #161616 100%)",
background: 'radial-gradient(50% 50% at 50% 50%, #0058DB 0%, #161616 100%)',
},
{
background: "radial-gradient(50% 50% at 50% 50%, #0058DB 0%, #161616 100%)",
background: 'radial-gradient(50% 50% at 50% 50%, #0058DB 0%, #161616 100%)',
},
];

const BgLoop = (text: any, ctaRef: RefObject<HTMLDivElement | null>) => {
const BgLoop = (text: Item['text'], ctaRef: RefObject<HTMLDivElement | null>) => {
return (
<div
ref={ctaRef}
className="flex select-none opacity-100 transition-opacity duration-1000"
>
<div ref={ctaRef} className="flex select-none opacity-100 transition-opacity duration-1000">
<div className="flex w-full flex-row justify-end">
<div
className={`flex w-full ${
text.cta ? "max-w-[316px]" : "max-w-[605px]"
} flex-col 3xl:max-w-4xl`}
>
<h1
className="text-6xl font-semibold 3xl:text-7xl"
style={{ lineHeight: 1 }}
>
<div className={`flex w-full ${text.cta ? 'max-w-[316px]' : 'max-w-[605px]'} flex-col 3xl:max-w-4xl`}>
<h1 className="text-6xl font-semibold 3xl:text-7xl" style={{ lineHeight: 1 }}>
{text.title}
</h1>
<p className="mt-6 text-xl font-medium 3xl:text-2xl">
{text.description}
</p>
<p className="mt-6 text-xl font-medium 3xl:text-2xl">{text.description}</p>
{text.cta ? (
<div
onClick={() => {
window.open(text.ctaLink, "_blank");
window.open(text.ctaLink, '_blank');
}}
className="mt-5 flex cursor-pointer flex-row items-center space-x-1 hover:underline"
>
Expand All @@ -96,10 +93,10 @@ export default function Layout({
const ctaRef = useRef<HTMLDivElement>(null);
const imageRef = useRef<HTMLDivElement>(null);
const [imagesLoaded, setImagesLoaded] = useState<string[]>([]);
let height = useRef(window.innerHeight);
const [item, setItem] = useState<Record<string, any>>({
const height = useRef(window.innerHeight);
const [item, setItem] = useState<Item>({
text: heroSectionTextPaths[0],
image: "",
image: '',
background: backgroundColor[0],
});

Expand All @@ -123,13 +120,13 @@ export default function Layout({

const background = new Image();
background.src = `${window.origin}/bg.png`;
background.addEventListener("load", () => {
backgroundRef.current?.classList.remove("opacity-0");
backgroundRef.current?.classList.add("opacity-100");
background.addEventListener('load', () => {
backgroundRef.current?.classList.remove('opacity-0');
backgroundRef.current?.classList.add('opacity-100');
});
}, []);

ctaRef.current?.classList.add("opacity-100");
ctaRef.current?.classList.add('opacity-100');

useEffect(() => {
let currentIndex = 0;
Expand All @@ -145,12 +142,12 @@ export default function Layout({
const newBg = backgroundColor[currentIndex];

// Fade out
ctaRef.current?.classList.remove("opacity-100");
ctaRef.current?.classList.add("opacity-0");
backgroundRef.current?.classList.remove("opacity-100");
backgroundRef.current?.classList.add("opacity-0");
imageRef.current?.classList.remove("opacity-100");
imageRef.current?.classList.add("opacity-0");
ctaRef.current?.classList.remove('opacity-100');
ctaRef.current?.classList.add('opacity-0');
backgroundRef.current?.classList.remove('opacity-100');
backgroundRef.current?.classList.add('opacity-0');
imageRef.current?.classList.remove('opacity-100');
imageRef.current?.classList.add('opacity-0');

// Update text and image
setTimeout(() => {
Expand All @@ -170,33 +167,33 @@ export default function Layout({

setTimeout(() => {
// Fade in
ctaRef.current?.classList.remove("opacity-0");
ctaRef.current?.classList.add("opacity-100");
backgroundRef.current?.classList.remove("opacity-0");
backgroundRef.current?.classList.add("opacity-100");
imageRef.current?.classList.remove("opacity-0");
imageRef.current?.classList.add("opacity-100");
ctaRef.current?.classList.remove('opacity-0');
ctaRef.current?.classList.add('opacity-100');
backgroundRef.current?.classList.remove('opacity-0');
backgroundRef.current?.classList.add('opacity-100');
imageRef.current?.classList.remove('opacity-0');
imageRef.current?.classList.add('opacity-100');
}, 1000); // Wait for fade out animation to complete
}, 7000); // 10 seconds

return () => clearInterval(interval);
}, [imagesLoaded]);

useEffect(() => {
window.addEventListener("resize", () => {
window.addEventListener('resize', () => {
height.current = window.innerHeight;
});

return () => {
window.removeEventListener("resize", () => {});
window.removeEventListener('resize', () => {});
};
}, []);

return (
<>
<Navbar />
<div
className="relative flex w-auto flex-col justify-center overflow-hidden bg-white lg:min-h-[700px] lg:bg-black "
className="relative flex w-auto flex-col justify-center overflow-hidden bg-white lg:min-h-[700px] lg:bg-black"
style={{ height: height.current }}
>
<div
Expand All @@ -205,41 +202,35 @@ export default function Layout({
className="absolute inset-0 block bg-cover bg-center bg-no-repeat opacity-0 transition-opacity duration-500"
/>
<div className="relative min-h-0 flex-1 lg:py-0 lg:pt-24">
<div className="relative flex h-full max-w-screen-xl flex-col items-center justify-center md:px-10 xl:mx-auto xl:px-0 3xl:max-w-full">
<div className="relative flex h-full w-full flex-row items-center justify-start space-x-20 lg:pb-32 3xl:translate-x-50">
<div
className="relative flex h-full max-w-screen-xl flex-col items-center justify-center md:px-10
xl:mx-auto xl:px-0 3xl:max-w-full"
>
<div
className="relative flex h-full w-full flex-row items-center justify-start space-x-20
lg:pb-32 3xl:translate-x-50"
>
<div className="relative flex h-full w-full items-center lg:w-max">
<Card className="relative z-30 flex shrink-0 flex-col pt-12 md:pt-0">
{children}
</Card>
</div>
<div className="hidden text-white lg:block">
{BgLoop(item.text, ctaRef)}
<Card className="relative z-30 flex shrink-0 flex-col pt-12 md:pt-0">{children}</Card>
</div>
<div className="hidden text-white lg:block">{BgLoop(item.text, ctaRef)}</div>
</div>
{hasContentBelow &&
{hasContentBelow && (
<div className="absolute bottom-12 hidden lg:flex">
<ArrowCircleDown
size={32}
className="animate-bounce text-white"
/>
<ArrowCircleDown size={32} className="animate-bounce text-white" />
</div>
}
)}
</div>
</div>

{item.image && (
<div
ref={imageRef}
className={`absolute ${
item.image === imagesLoaded[3] && "bottom-0"
} right-0 hidden w-full max-w-[700px] translate-x-50 opacity-0 transition-opacity duration-1000 xl:flex 3xl:right-10 3xl:w-full 3xl:max-w-4xl 3xl:translate-x-0 3xl:items-center 3xl:justify-center`}
className={`absolute ${item.image === imagesLoaded[3] && 'bottom-0'} right-0 hidden w-full max-w-[700px]
translate-x-50 opacity-0 transition-opacity duration-1000 xl:flex 3xl:right-10 3xl:w-full 3xl:max-w-4xl
3xl:translate-x-0 3xl:items-center 3xl:justify-center`}
>
<img
src={item.image}
alt={item.text.title}
draggable={false}
loading="lazy"
/>
<img src={item.image} alt={item.text.title} draggable={false} loading="lazy" />
</div>
)}
</div>
Expand Down
16 changes: 5 additions & 11 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ReactNode } from "react";
import { ReactNode } from 'react';

export default function Button({
className = "",
className = '',
children,
disabled,
outline,
Expand All @@ -13,17 +13,11 @@ export default function Button({
outline?: boolean;
onClick?: () => void;
}) {
const background = outline
? "bg-transparent"
: "bg-primary active:bg-primary-dark disabled:bg-gray-40";
const background = outline ? 'bg-transparent' : 'bg-primary active:bg-primary-dark disabled:bg-gray-40';

const textColor = outline
? "text-primary active:text-primary-dark disabled:text-gray-40"
: "text-white";
const textColor = outline ? 'text-primary active:text-primary-dark disabled:text-gray-40' : 'text-white';

const border = outline
? "border border-primary active:border-primary-dark disabled:border-gray-40"
: "";
const border = outline ? 'border border-primary active:border-primary-dark disabled:border-gray-40' : '';

return (
<button
Expand Down
16 changes: 3 additions & 13 deletions src/components/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import { ReactNode } from "react";
import { ReactNode } from 'react';

export default function Card({
className = "",
children,
}: {
className?: string;
children?: ReactNode;
}) {
export default function Card({ className = '', children }: { className?: string; children?: ReactNode }) {
return (
<div
className={`${className} h-full w-full bg-white lg:max-h-[750px] lg:w-96 lg:rounded-2xl`}
>
{children}
</div>
<div className={`${className} h-full w-full bg-white lg:max-h-[750px] lg:w-96 lg:rounded-2xl`}>{children}</div>
);
}
2 changes: 1 addition & 1 deletion src/components/CardBotton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode } from "react";
import { ReactNode } from 'react';

export default function CardBottom({ children }: { children: ReactNode }) {
return (
Expand Down
6 changes: 4 additions & 2 deletions src/components/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default function Dropdown({
menuItems,
classMenuItems,
openDirection,
buttonInputRef
buttonInputRef,
}: {
children: ReactNode;
classButton?: string;
Expand All @@ -19,7 +19,9 @@ export default function Dropdown({
return (
<Menu>
<div className="relative flex items-center">
<Menu.Button className={`outline-hidden cursor-pointer ${classButton}`} ref={buttonInputRef}>{children}</Menu.Button>
<Menu.Button className={`outline-hidden cursor-pointer ${classButton}`} ref={buttonInputRef}>
{children}
</Menu.Button>

<Transition
enter="transform transition duration-50 ease-out"
Expand Down
Loading