diff --git a/packages/nextjs/app/builders/0x8Bb563DC969cC3b3e7275474c3847b44dBCB9441/page.tsx b/packages/nextjs/app/builders/0x8Bb563DC969cC3b3e7275474c3847b44dBCB9441/page.tsx index 2bd3ddf..4ea5e0f 100644 --- a/packages/nextjs/app/builders/0x8Bb563DC969cC3b3e7275474c3847b44dBCB9441/page.tsx +++ b/packages/nextjs/app/builders/0x8Bb563DC969cC3b3e7275474c3847b44dBCB9441/page.tsx @@ -13,7 +13,7 @@ const MichaelEsenwa: NextPage = () => { Hi there, I am Kachukwu Michael Esenwa{" "}
- avatar + avatar

@@ -42,7 +42,7 @@ const MichaelEsenwa: NextPage = () => {
- avatar + avatar
diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index 5a377e0..50b19d6 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -1,9 +1,13 @@ "use client"; +import Image from "next/image"; import Link from "next/link"; +import "../styles/LandingPage.css"; +import ShootingStars from "./builders/0x28482B1279E442f49eE76351801232D58f341CB9/components/ShootingStars"; import type { NextPage } from "next"; import { useAccount } from "wagmi"; import { BugAntIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { StarsBackground } from "~~/components/StarsBg"; import { Address } from "~~/components/scaffold-eth"; import { useScaffoldReadContract } from "~~/hooks/scaffold-eth"; @@ -19,18 +23,34 @@ interface BatchUserStatus { isLoading: boolean; } +const images = [ + "/bello/bello.jpg", + "/dvm0x742/avatar.jpg", + "/lukmansImages/lukmansAvater.jpeg", + "/michaelNwachukwu-images/michael-nwachukwu.png", + "https://avatars.githubusercontent.com/u/42065630?v=5", + "/0x26BfbD8ED2B302ec2c2B6f063C4caF7abcB062e0-avatar.jpg", + "/avatar.webp", + "/emarc-pixels.jpg", + "/superior.jpeg", + "/cherry/cherrypfp.png", + "https://avatars.githubusercontent.com/u/141290516?v=3", +]; + const Alert = ({ children, className = "" }: Props) => (
{children}
); -const AlertTitle = ({ children }: Props) => ( -
{children}
+const AlertTitle = ({ children, className }: Props) => ( +
{children}
); -const AlertDescription = ({ children }: Props) =>
{children}
; +const AlertDescription = ({ children, className }: Props) => ( +
{children}
+); const Card = ({ children, className = "" }: Props) => ( -
+
{children}
); @@ -39,8 +59,8 @@ const CardHeader = ({ children, className = "" }: Props) => (
{children}
); -const CardTitle = ({ children }: Props) => ( -

{children}

+const CardTitle = ({ children, className }: Props) => ( +

{children}

); const CardContent = ({ children, className = "" }: Props) =>
{children}
; @@ -52,8 +72,8 @@ const StatusSection = ({ connectedAddress, isAllowListed, isCheckedIn, isLoading
-
-

Checking your status...

+
+

Checking your status...

@@ -64,8 +84,10 @@ const StatusSection = ({ connectedAddress, isAllowListed, isCheckedIn, isLoading if (!connectedAddress) { return ( - Connect Your Wallet - Please connect your wallet to view your Batch 10 status + Connect Your Wallet + + Please connect your wallet to view your Batch 10 status + ); } @@ -75,12 +97,12 @@ const StatusSection = ({ connectedAddress, isAllowListed, isCheckedIn, isLoading
- Your Status - Not a Member + Your Status + Not a Member
-

You are not currently a member of Batch 10

+

You are not currently a member of Batch 10

); @@ -91,29 +113,31 @@ const StatusSection = ({ connectedAddress, isAllowListed, isCheckedIn, isLoading
- Your Status - + Your Status + Ready to Check In
-

You are a Batch 10 member! Deploy your contract to check in

+

+ You are a Batch 10 member! Deploy your contract to check in +

); } return ( - +
- Your Status - Checked In + Your Status + Checked In
-
+
Active with wallet address:
@@ -158,62 +182,79 @@ const Home: NextPage = () => { const isCheckedIn = userContractAddress && userContractAddress !== "0x0000000000000000000000000000000000000000"; return ( -
-
-

- Welcome to - Batch 10 -

-

Get started by taking a look at your batch GitHub repository.

- - {error ? ( -
-

Error fetching contract data: {error.message}

-
- ) : ( -
-
- Checked in builders count: - {counterLoading ? ( - -
-
- ) : ( - {checkedInCounter !== undefined ? Number(checkedInCounter) : "0"} - )} +
+ + +
+
+ {images.map((image, index) => ( +
+ {`builder
- - + ))} +
+
+

+ BATCH 10 +

+
+

Buidl Guidl

- )} +
+
+
+
+ {error ? ( +
+

Error fetching contract data: {error.message}

+
+ ) : ( +
+
+ Checked in builders count: + {counterLoading ? ( + +
+
+ ) : ( + + {checkedInCounter !== undefined ? Number(checkedInCounter) : "0"} + + )} +
-
-
-
- -

- Tinker with your smart contract using the{" "} - - Debug Contracts - {" "} - tab. -

-
-
- -

- Explore your local transactions with the{" "} - - Block Explorer - {" "} - tab. -

+ +
+ )} +
+
+
+
+ +

+ Tinker with your smart contract using the{" "} + + Debug Contracts + {" "} + tab. +

+
+
+ +

+ Explore your local transactions with the{" "} + + Block Explorer + {" "} + tab. +

+
diff --git a/packages/nextjs/components/StarsBg.tsx b/packages/nextjs/components/StarsBg.tsx new file mode 100644 index 0000000..f542896 --- /dev/null +++ b/packages/nextjs/components/StarsBg.tsx @@ -0,0 +1,113 @@ +"use client"; + +import React, { RefObject, useCallback, useEffect, useRef, useState } from "react"; + +interface StarProps { + x: number; + y: number; + radius: number; + opacity: number; + twinkleSpeed: number | null; +} + +interface StarBackgroundProps { + starDensity?: number; + allStarsTwinkle?: boolean; + twinkleProbability?: number; + minTwinkleSpeed?: number; + maxTwinkleSpeed?: number; + className?: string; +} + +export const StarsBackground: React.FC = ({ + starDensity = 0.00015, + allStarsTwinkle = true, + twinkleProbability = 0.7, + minTwinkleSpeed = 0.5, + maxTwinkleSpeed = 1, + className, +}) => { + const [stars, setStars] = useState([]); + const canvasRef: RefObject = useRef(null); + + const generateStars = useCallback( + (width: number, height: number): StarProps[] => { + const area = width * height; + const numStars = Math.floor(area * starDensity); + return Array.from({ length: numStars }, () => { + const shouldTwinkle = allStarsTwinkle || Math.random() < twinkleProbability; + return { + x: Math.random() * width, + y: Math.random() * height, + radius: Math.random() * 0.05 + 0.5, + opacity: Math.random() * 0.5 + 0.5, + twinkleSpeed: shouldTwinkle ? minTwinkleSpeed + Math.random() * (maxTwinkleSpeed - minTwinkleSpeed) : null, + }; + }); + }, + [starDensity, allStarsTwinkle, twinkleProbability, minTwinkleSpeed, maxTwinkleSpeed], + ); + + useEffect(() => { + const updateStars = () => { + if (canvasRef.current) { + const canvas = canvasRef.current; + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + const { width, height } = canvas.getBoundingClientRect(); + canvas.width = width; + canvas.height = height; + setStars(generateStars(width, height)); + } + }; + + updateStars(); + + const resizeObserver = new ResizeObserver(updateStars); + const currentCanvas = canvasRef.current; // Copy the ref value to a variable + if (currentCanvas) { + resizeObserver.observe(currentCanvas); + } + + return () => { + if (currentCanvas) { + resizeObserver.unobserve(currentCanvas); + } + }; + }, [starDensity, allStarsTwinkle, twinkleProbability, minTwinkleSpeed, maxTwinkleSpeed, generateStars]); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + let animationFrameId: number; + + const render = () => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + stars.forEach(star => { + ctx.beginPath(); + ctx.arc(star.x, star.y, star.radius, 0, Math.PI * 2); + ctx.fillStyle = `rgba(255, 255, 255, ${star.opacity})`; + ctx.fill(); + + if (star.twinkleSpeed !== null) { + star.opacity = 0.5 + Math.abs(Math.sin((Date.now() * 0.001) / star.twinkleSpeed) * 0.5); + } + }); + + animationFrameId = requestAnimationFrame(render); + }; + + render(); + + return () => { + cancelAnimationFrame(animationFrameId); + }; + }, [stars]); + + return ; +}; diff --git a/packages/nextjs/public/cherry/cherrypfp.png b/packages/nextjs/public/cherry/cherrypfp.png new file mode 100644 index 0000000..cda0c79 Binary files /dev/null and b/packages/nextjs/public/cherry/cherrypfp.png differ diff --git a/packages/nextjs/public/guild.png b/packages/nextjs/public/guild.png new file mode 100755 index 0000000..f0322f9 Binary files /dev/null and b/packages/nextjs/public/guild.png differ diff --git a/packages/nextjs/styles/LandingPage.css b/packages/nextjs/styles/LandingPage.css new file mode 100644 index 0000000..47a2086 --- /dev/null +++ b/packages/nextjs/styles/LandingPage.css @@ -0,0 +1,133 @@ +@import url("https://fonts.cdnfonts.com/css/ica-rubrik-black"); +@import url("https://fonts.cdnfonts.com/css/poppins"); + +.banner { + width: 100%; + height: 100vh; + text-align: center; + overflow: hidden; + position: relative; + background: #25283b22; +} +.banner .slider { + position: absolute; + width: 200px; + height: 200px; + top: 10%; + left: calc(50% - 100px); + transform-style: preserve-3d; + transform: perspective(1000px); + animation: autoRun 20s linear infinite; + z-index: 2; + -webkit-transform: perspective(1000px); + -moz-transform: perspective(1000px); + -ms-transform: perspective(1000px); + -o-transform: perspective(1000px); +} +@keyframes autoRun { + from { + transform: perspective(1000px) rotateX(-16deg) rotateY(0deg); + } + to { + transform: perspective(1000px) rotateX(-16deg) rotateY(360deg); + } +} + +.banner .slider .item { + position: absolute; + inset: 0 0 0 0; + transform: rotateY(calc((var(--position) - 1) * (360 / var(--quantity)) * 1deg)) translateZ(550px); +} +.banner .slider .item img { + width: 100%; + height: 100%; + object-fit: cover; +} +.banner .content { + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + width: min(1400px, 100vw); + height: max-content; + padding-bottom: 100px; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + z-index: 1; +} +.banner .content h1 { + font-family: "ICA Rubrik"; + font-size: 16em; + line-height: 1em; + color: #25283b; + position: relative; +} +.banner .content h1::after { + position: absolute; + inset: 0 0 0 0; + content: attr(data-content); + z-index: 2; + -webkit-text-stroke: 2px #d2d2d2; + color: transparent; +} +.banner .content .author { + font-family: Poppins; + text-align: right; + max-width: 200px; +} +.banner .content h2 { + font-size: 3em; +} +.banner .content .model { + background-image: url(/guild.png); + width: 100%; + height: 75vh; + position: absolute; + bottom: 0; + left: 0; + background-size: auto 100%; + background-repeat: no-repeat; + background-position: top center; + z-index: 1; +} +@media screen and (max-width: 1023px) { + .banner .slider { + width: 160px; + height: 200px; + left: calc(50% - 80px); + } + .banner .slider .item { + transform: rotateY(calc((var(--position) - 1) * (360 / var(--quantity)) * 1deg)) translateZ(300px); + } + .banner .content h1 { + text-align: center; + width: 100%; + text-shadow: 0 10px 20px #000; + font-size: 7em; + } + .banner .content .author { + color: #fff; + padding: 20px; + text-shadow: 0 10px 20px #000; + z-index: 2; + max-width: unset; + width: 100%; + text-align: center; + padding: 0 30px; + } +} +@media screen and (max-width: 767px) { + .banner .slider { + width: 100px; + height: 150px; + left: calc(50% - 50px); + } + .banner .slider .item { + transform: rotateY(calc((var(--position) - 1) * (360 / var(--quantity)) * 1deg)) translateZ(180px); + } + .banner .content h1 { + font-size: 5em; + } +}