Finished a first pass of the project section

This commit is contained in:
2023-05-12 00:31:11 -05:00
parent 8f738b0ad2
commit 317081841c
7 changed files with 106 additions and 28 deletions

View File

@@ -0,0 +1,5 @@
import type { PropsWithChildren } from "react";
export const Container: React.FC<PropsWithChildren> = ({ children }) => {
return <div className="container">{children}</div>;
};

View File

@@ -1,4 +1,6 @@
import Image from "next/image";
import { useEffect, useRef, useState } from "react";
import useIntersectionObserver from "~/hooks/useIntersectionObserver";
export interface Props {
title: string;
@@ -7,6 +9,18 @@ export interface Props {
}
export const Polaroid: React.FC<Props> = ({ title, imageSrc, rotation }) => {
const [showImage, setShowImage] = useState(false);
const ref = useRef<HTMLDivElement | null>(null);
const entry = useIntersectionObserver(ref, {});
const isOnScreen = !!entry?.isIntersecting;
useEffect(() => {
if (isOnScreen) {
setShowImage(true);
}
}, [isOnScreen]);
return (
<div
className={`m-5 w-52 rounded bg-[#F8F2EA] text-black shadow-md sm:w-64 lg:w-80 ${rotation}`}
@@ -14,13 +28,20 @@ export const Polaroid: React.FC<Props> = ({ title, imageSrc, rotation }) => {
<div className="flex h-full w-full flex-col items-center justify-between gap-y-3 p-4 sm:gap-y-4 sm:p-5 lg:gap-y-5 lg:p-6">
<div className="relative aspect-square w-full">
<Image
src="https://picsum.photos/200"
src={imageSrc}
alt={`Showcase of ${title}`}
fill
className="object-cover shadow-inner"
/>
<div
className={`absolute inset-0 transition-colors duration-1000 ${
showImage ? "bg-transparent" : "bg-[#3D3D3D]"
}`}
/>
</div>
<span className="text-2xl font-semibold">{title}</span>
<span ref={ref} className="text-2xl font-semibold">
{title}
</span>
</div>
</div>
);

View File

@@ -12,8 +12,8 @@ export const ProjectDescription: React.FC<Props> = ({
children,
}) => {
return (
<div className="max-w-5xl text-black">
<h2 className="text-3xl font-semibold">{title}</h2>
<div className="max-w-4xl text-black">
<h3 className="text-3xl font-semibold">{title}</h3>
<Separator.Root
className={`${color} my-2 h-1 w-full rounded-full`}
decorative

View File

@@ -10,6 +10,7 @@ const roadster = localFont({
preload: true,
variable: "--font-roadster",
});
const jakarta = Plus_Jakarta_Sans({
subsets: ["latin"],
weight: ["400", "600", "800"],

View File

@@ -5,7 +5,7 @@ export const projects: Array<PolaroidProps & ProjectDescriptionProps> = [
{
title: "Parallel",
color: "bg-orange",
imageSrc: "https://unsplash.com/photos/OqtafYT5kTw",
imageSrc: "https://picsum.photos/seed/Parallel/200",
rotation: "-rotate-12",
children:
"We started Parallel to help connect educators with content creators to make it easier to create high-quality educational content for platforms like YouTube. We built the platform with high performance, scalability, and accessibility in mind. That's why we chose powerful tools like Next.js, TailwindCSS, RadixUI, Prisma, PlanetScale, and Vercel's hosting platform. ",
@@ -13,15 +13,15 @@ export const projects: Array<PolaroidProps & ProjectDescriptionProps> = [
{
title: "DropNote",
color: "bg-yellow",
imageSrc: "",
imageSrc: "https://picsum.photos/seed/DropNote/200",
rotation: "rotate-6",
children:
"We started Parallel to help connect educators with content creators to make it easier to create high-quality educational content for platforms like YouTube. We built the platform with high performance, scalability, and accessibility in mind. That's why we chose powerful tools like Next.js, TailwindCSS, RadixUI, Prisma, PlanetScale, and Vercel's hosting platform. ",
},
{
title: "Flurry",
title: "Flurry Waitlist",
color: "bg-green",
imageSrc: "",
imageSrc: "https://picsum.photos/seed/Flurry/200",
rotation: "-rotate-3",
children:
"We started Parallel to help connect educators with content creators to make it easier to create high-quality educational content for platforms like YouTube. We built the platform with high performance, scalability, and accessibility in mind. That's why we chose powerful tools like Next.js, TailwindCSS, RadixUI, Prisma, PlanetScale, and Vercel's hosting platform. ",

View File

@@ -0,0 +1,45 @@
import { type RefObject, useEffect, useState } from "react";
interface Args extends IntersectionObserverInit {
freezeOnceVisible?: boolean;
}
function useIntersectionObserver(
elementRef: RefObject<Element>,
{
threshold = 0,
root = null,
rootMargin = "0%",
freezeOnceVisible = false,
}: Args
): IntersectionObserverEntry | undefined {
const [entry, setEntry] = useState<IntersectionObserverEntry>();
const frozen = entry?.isIntersecting && freezeOnceVisible;
const updateEntry = ([entry]: IntersectionObserverEntry[]): void => {
setEntry(entry);
};
const stringifiedThreshold = JSON.stringify(threshold);
useEffect(() => {
const node = elementRef?.current; // DOM Ref
const hasIOSupport = !!window.IntersectionObserver;
if (!hasIOSupport || frozen || !node) return;
const observerParams = { threshold, root, rootMargin };
const observer = new IntersectionObserver(updateEntry, observerParams);
observer.observe(node);
return () => observer.disconnect();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [elementRef?.current, stringifiedThreshold, root, rootMargin, frozen]);
return entry;
}
export default useIntersectionObserver;

View File

@@ -1,5 +1,6 @@
import { type NextPage } from "next";
import Head from "next/head";
import { Container } from "~/components/Container";
import { Polaroid } from "~/components/Polaroid";
import { ProjectDescription } from "~/components/ProjectDescription";
import { projects } from "~/constants/projects";
@@ -43,27 +44,32 @@ const Hero = () => {
const Projects = () => {
return (
<div className="container py-20 [&>*:nth-child(odd)]:md:flex-row">
{projects.map((p) => (
<div
key={p.title}
className="my-20 flex flex-col items-center gap-x-12 gap-y-6 md:my-0 md:flex-row-reverse"
>
<div className="">
<Polaroid
title={p.title}
imageSrc={p.imageSrc}
rotation={p.rotation}
/>
<Container>
<h2 className="text-center text-4xl font-extrabold text-black">
Here are some of our past projects
</h2>
<div className="py-20 [&>*:nth-child(odd)]:md:flex-row">
{projects.map((p) => (
<div
key={p.title}
className="my-20 flex flex-col items-center gap-x-12 gap-y-6 md:my-0 md:flex-row-reverse"
>
<div>
<Polaroid
title={p.title}
imageSrc={p.imageSrc}
rotation={p.rotation}
/>
</div>
<div>
<ProjectDescription title={p.title} color={p.color}>
{p.children}
</ProjectDescription>
</div>
</div>
<div className="">
<ProjectDescription title={p.title} color={p.color}>
{p.children}
</ProjectDescription>
</div>
</div>
))}
</div>
))}
</div>
</Container>
);
};