diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx index 6ccad0d..842210c 100644 --- a/src/app/about/page.tsx +++ b/src/app/about/page.tsx @@ -1,8 +1,41 @@ -'use client'; +"use client"; +import React, { useState } from "react"; export default function About() { + const [isHovered, setIsHovered] = useState(false); + return ( - <>about +
+
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + > + {/* Main text */} +

+ COMING +

+

+ SOON! +

+ + {/* Animated underline */} +
+
+
+ + {/* Subtitle */} +

+ We're building something awesome. +
+ Stay tuned! +

+
+
); } diff --git a/src/app/api/instagram-count/route.ts b/src/app/api/instagram-count/route.ts index 9865d5c..e46d83f 100644 --- a/src/app/api/instagram-count/route.ts +++ b/src/app/api/instagram-count/route.ts @@ -1,60 +1,47 @@ import { NextResponse } from "next/server"; -import puppeteer from "puppeteer"; export async function GET() { - let browser; try { - browser = await puppeteer.launch({ - headless: true, - args: ["--no-sandbox", "--disable-setuid-sandbox"], + const response = await fetch("https://www.instagram.com/pcbuildinguf/", { + headers: { + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36", + Accept: + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Language": "en-US,en;q=0.5", + "Cache-Control": "no-cache", + Pragma: "no-cache", + }, }); - const page = await browser.newPage(); - - // Set a user agent to appear more like a regular browser - await page.setUserAgent( - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36", - ); + if (!response.ok) { + throw new Error("Failed to fetch Instagram page"); + } - // Navigate to the Instagram profile - await page.goto("https://www.instagram.com/pcbuildinguf/", { - waitUntil: "networkidle0", - timeout: 30000, - }); + const html = await response.text(); - // Wait for the followers count to be visible - await page.waitForSelector('meta[property="og:description"]', { - timeout: 5000, - }); + // Try to find the followers count in the JSON data that Instagram embeds + const jsonMatch = html.match(/"edge_followed_by":{"count":(\d+)}/); + if (jsonMatch && jsonMatch[1]) { + const followerCount = parseInt(jsonMatch[1]); + return NextResponse.json({ followerCount }); + } - // Get the meta tag content - const metaContent = await page.$eval( - 'meta[property="og:description"]', - (element) => element.content, + // Fallback: try to find it in meta tags + const metaMatch = html.match( + /]*?og:description[^>]*?content="[^"]*?(\d+)\s+Followers/i, ); - - // Extract follower count from meta content - const followerMatch = metaContent.match(/([0-9,.]+)\s*Followers/i); - const followerCount = followerMatch - ? parseInt(followerMatch[1].replace(/,/g, "")) - : null; - - console.log("Fetched content:", metaContent); // For debugging - - if (!followerCount) { - throw new Error("Could not extract follower count"); + if (metaMatch && metaMatch[1]) { + const followerCount = parseInt(metaMatch[1]); + return NextResponse.json({ followerCount }); } - return NextResponse.json({ followerCount }); + throw new Error("Could not find follower count"); } catch (error) { console.error("Error fetching Instagram count:", error); - return NextResponse.json( - { error: "Failed to fetch follower count" }, - { status: 500 }, - ); - } finally { - if (browser) { - await browser.close(); - } + + // Return a fallback count if scraping fails + // You can store this in an environment variable or database + return NextResponse.json({ followerCount: 908 }); } } diff --git a/src/app/projects/page.tsx b/src/app/projects/page.tsx index 55d258a..160966c 100644 --- a/src/app/projects/page.tsx +++ b/src/app/projects/page.tsx @@ -1,5 +1,41 @@ "use client"; +import React, { useState } from "react"; + export default function Projects() { - return <>Projects page; + const [isHovered, setIsHovered] = useState(false); + + return ( +
+
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + > + {/* Main text */} +

+ COMING +

+

+ SOON! +

+ + {/* Animated underline */} +
+
+
+ + {/* Subtitle */} +

+ We're building something awesome. +
+ Stay tuned! +

+
+
+ ); } diff --git a/src/components/MemberCounts/SocialStats.tsx b/src/components/MemberCounts/SocialStats.tsx index b0ff3fe..a5a7d71 100644 --- a/src/components/MemberCounts/SocialStats.tsx +++ b/src/components/MemberCounts/SocialStats.tsx @@ -29,7 +29,7 @@ const StatCard: React.FC = ({ rel="noopener noreferrer" className="block transition-transform duration-300 hover:scale-105" > -
+
{/* Glow effect on hover */}
{ glowColor="rgba(88, 101, 242, 0.5)" href="https://discord.com/invite/jfq9phWqTF" /> - { bgColor="bg-gradient-to-tr from-[#F58529] via-[#DD2A7B] to-[#8134AF]" glowColor="rgba(221, 42, 123, 0.5)" href="https://www.instagram.com/pcbuildinguf/" - /> + /> */}
); }; diff --git a/src/components/landing/Hero.tsx b/src/components/landing/Hero.tsx index 0fdb902..08bf8a5 100644 --- a/src/components/landing/Hero.tsx +++ b/src/components/landing/Hero.tsx @@ -1,27 +1,58 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import LogoCarousel from "./LogoCarousel"; import Image from "next/image"; import { motion } from "framer-motion"; +import SocialStats from "@/components/MemberCounts/SocialStats"; export default function Hero() { + const [text, setText] = useState(""); + const [isInitialBlinkComplete, setIsInitialBlinkComplete] = useState(false); + const fullText = "The Society of PC Building"; + const [isTypingComplete, setIsTypingComplete] = useState(false); + + // Handle initial cursor blink + useEffect(() => { + // Wait for 2 full blink cycles (2 seconds) before starting the typing + const initialBlinkTimeout = setTimeout(() => { + setIsInitialBlinkComplete(true); + }, 400); // 2 seconds = 2 full blink cycles at 1s per cycle + + return () => clearTimeout(initialBlinkTimeout); + }, []); + + // Handle typing animation + useEffect(() => { + if (!isInitialBlinkComplete) return; // Don't start typing until initial blink is complete + + if (text.length < fullText.length) { + const timeout = setTimeout(() => { + setText(fullText.slice(0, text.length + 1)); + }, 70); // Adjust typing speed here (milliseconds) + + return () => clearTimeout(timeout); + } else { + setIsTypingComplete(true); + } + }, [text, isInitialBlinkComplete, fullText]); + return (
- {/* Flex-row on desktop devices but flex-col-reverse for devices lg and smaller */}
- {/* Hidden on mobile */} - - 1000+ Active Members! - -

- The Society of PC Building +

+ {text} + + _ +

- {/* On mobile devices shorten the description to limit text-length */} -

+

Join the Society of PC Building at UF—where @@ -29,18 +60,28 @@ export default function Hero() { hardware and tech connect, innovate, and build custom PCs together.

+ + + + - Join the Club! + Get Involved! - {/* On mobile devices show the infinite carousel but on desktop static list */} -
-

+

+

Led by a team of officers with experience at:

@@ -56,19 +97,20 @@ export default function Hero() {
- {/* Animate SPCB logo upwards. Applied negative margin to center logo better */}