From e8c350e4206ecbe40a82092d6be4b5535df7c07a Mon Sep 17 00:00:00 2001 From: suvanbanerjee Date: Fri, 16 Aug 2024 23:30:43 +0530 Subject: [PATCH 1/2] ui changes --- app/(default)/page.tsx | 17 +- app/(default)/sihregistration/page.tsx | 10 +- app/css/additional-styles/form.css | 20 +-- components/activities.tsx | 131 +++++++++++++++ components/eventcards.tsx | 52 ++++++ components/forms/sihForm.tsx | 3 +- components/hero.tsx | 29 ++-- components/landing.tsx | 218 ------------------------- components/leads.tsx | 33 ++++ components/magicui/flickering-grid.tsx | 184 +++++++++++++++++++++ components/magicui/gradual-spacing.tsx | 44 +++++ components/magicui/hyper-text.tsx | 89 ++++++++++ components/magicui/sparkles-text.tsx | 152 +++++++++++++++++ 13 files changed, 718 insertions(+), 264 deletions(-) create mode 100644 components/activities.tsx create mode 100644 components/eventcards.tsx delete mode 100644 components/landing.tsx create mode 100644 components/leads.tsx create mode 100644 components/magicui/flickering-grid.tsx create mode 100644 components/magicui/gradual-spacing.tsx create mode 100644 components/magicui/hyper-text.tsx create mode 100644 components/magicui/sparkles-text.tsx diff --git a/app/(default)/page.tsx b/app/(default)/page.tsx index 90d29cc..77a8f3e 100644 --- a/app/(default)/page.tsx +++ b/app/(default)/page.tsx @@ -6,35 +6,38 @@ export const metadata = { import Hero from "@/components/hero"; import Domains from "@/components/domains"; import "../css/additional-styles/landing.css"; -import Landing from "@/components/landing"; +import Activities from "@/components/activities"; import Image from "next/image"; import Link from "next/link"; +import SparklesText from "@/components/magicui/sparkles-text"; +import EventComponent from "@/components/eventcards"; +import Leads from "@/components/leads"; export default function Home() { return ( <>
-
- Upcoming Events -
+ sih -
- + + + ); } diff --git a/app/(default)/sihregistration/page.tsx b/app/(default)/sihregistration/page.tsx index 3eadad4..99ad0c1 100644 --- a/app/(default)/sihregistration/page.tsx +++ b/app/(default)/sihregistration/page.tsx @@ -7,20 +7,18 @@ import { cn } from "@/lib/utils"; const RegisterPage = () => { return ( -
+
-
-
+

- Register for Smart India Hackathon! + Register for Smart India Hackathon!

-
- +
+
+

Activities

+
+ + {/* CP Post */} +
+
+
+ +

PB Hustle

+

+ Point Blank has organized over 40+ editions of its PB Hustle + coding contest, where participants solve 5-7 increasingly + difficult problems in their preferred programming language. The + contest aims to enhance the programming culture in colleges and + help teams qualify for the ACM ICPC. Impressively, DSCE's leading + programmers have risen through this platform, with participation + in the CodeChef Long Challenge expanding from just 3 to over 70+ + participants. +

+
+
+
+
+ +
+
+
+ + {/* Development Post */} +
+
+
+ +
+
+
+
+ +

PB Chronicals

+

+ Point Blank has hosted over 100+ workshops, covering a wide range + of topics including open source, DevOps, machine learning, + placement preparation, data structures and algorithms, and mobile + and web development, among others. These workshops are typically + conducted in an informal and unscripted manner, though we do + document some of our most significant sessions. One notable + example is our primer on F/OSS development. +

+
+
+
+ + {/* Hackathon Post */} +
+
+
+ +

Smart India Hackathon

+

+ Each year, we organize the internal round of the Smart India + Hackathon. In the 2020 edition, over 300+ individuals from DSCE + participated. Two of our teams advanced to the finals, with one + emerging as the winner of the software edition. Along with this, + teams from Point Blank have won hackathons all across the city and + country. +

+
+
+
+
+ +
+
+
+ + {/* CyberSec Post */} +
+
+
+ +
+
+ +
+
+ +

PB CTF

+

+ We organize workshops and sessions on various topics in + cybersecurity, including hands-on practice on different platforms. + In 2023, we launched the first in-house Capture The Flag event, + PBCTF, which attracted over 70+ participants. +

+
+
+
+ + ); +} \ No newline at end of file diff --git a/components/eventcards.tsx b/components/eventcards.tsx new file mode 100644 index 0000000..3130ef4 --- /dev/null +++ b/components/eventcards.tsx @@ -0,0 +1,52 @@ +import React from "react"; + +const eventCard = [ + { + id: 1, + url: '/images/openday.jpg', + textt: "Tech Open Day", + textb: "Our first offline event of the year and it was a huge success✨Get to know about tech societies on campus and how to join them🚀", + }, + { + id: 2, + url: '/images/advaith.jpg', + textt: "Advaith", + textb: "An event full of opportunities, challenges, learning and much more! Be a part of something big, be a part of ADVAITH!", + }, + { + id: 3, + url: '/images/recruit.jpeg', + textt: "Recruitment 2024", + textb: "Recruitment 2024 is here! Join us and be a part of the Point Blank family!🚀", + }, +]; + +const EventComponent = () => { + return ( + <> +
+

Events

+
+ We organise lots of student centric activities +
+
+
+ {eventCard.map((ec) => ( +
+
+
+ {ec.textt} +
+
+

{ec.textt}

+

{ec.textb}

+
+
+
+ ))} +
+ + ); +}; + +export default EventComponent; \ No newline at end of file diff --git a/components/forms/sihForm.tsx b/components/forms/sihForm.tsx index 55dfc76..8ebb80b 100644 --- a/components/forms/sihForm.tsx +++ b/components/forms/sihForm.tsx @@ -115,11 +115,10 @@ const SIHMultiStepForm: React.FC = () => { return (
SIH -

SIH Registration Form

{/* Step 1: Team Information */} {step === 1 && ( diff --git a/components/hero.tsx b/components/hero.tsx index ed16c3e..d38e533 100644 --- a/components/hero.tsx +++ b/components/hero.tsx @@ -1,36 +1,37 @@ -import Logo from '@/public/images/logo.png' +import logo from '@/public/images/logo.svg' import Link from 'next/link' -import DotPattern from "@/components/magicui/dot-pattern"; +import Image from 'next/image' +import FlickeringGrid from "@/components/magicui/flickering-grid"; import { cn } from "@/lib/utils"; import "../app/css/additional-styles/landing.css"; export default function Hero() { return ( -
+
-

-

+ Logo +

+ We are a student run tech community at Dayananda Sagar College of Engineering, Bangalore. We aim to provide a platform for students to learn, grow and innovate. +

-
) diff --git a/components/landing.tsx b/components/landing.tsx deleted file mode 100644 index c2ac554..0000000 --- a/components/landing.tsx +++ /dev/null @@ -1,218 +0,0 @@ -import React from "react"; -import "../app/css/additional-styles/landing.css"; -import ImageOne from "../public/images/demo.jpg"; -import Image from "next/image"; - -export default function Landing() { - return ( - <> -
-

Activities

-
- We organise lots of student centric activities -
-
- -
-
-
-

- COMPETITIVE PROGRAMMING -

-

PB Hustle

-

- Point Blank has organized over 40+ editions of its PB Hustle - coding contest, where participants solve 5-7 increasingly - difficult problems in their preferred programming language. The - contest aims to enhance the programming culture in colleges and - help teams qualify for the ACM ICPC. Impressively, DSCE's leading - programmers have risen through this platform, with participation - in the CodeChef Long Challenge expanding from just 3 to over 70+ - participants. -

-
-
-
-
- -
-
-
- -
-
-
- -
-
-
-
-

DEVELOPMENT

-

PB Chronicals

-

- Point Blank has hosted over 100+ workshops, covering a wide range - of topics including open source, DevOps, machine learning, - placement preparation, data structures and algorithms, and mobile - and web development, among others. These workshops are typically - conducted in an informal and unscripted manner, though we do - document some of our most significant sessions. One notable - example is our primer on F/OSS development. -

-
-
-
- -
-
-
-

HACKATHONS

-

Smart India Hackathon

-

- Each year, we organize the internal round of the Smart India - Hackathon. In the 2020 edition, over 300+ individuals from DSCE - participated. Two of our teams advanced to the finals, with one - emerging as the winner of the software edition. Along with this, - teams from Point Blank have won hackathons all across the city and - country. -

-
-
-
-
- -
-
-
- -
-
-
- -
-
- -
-
-

CYBER SECURITY

-

PB CTF

-

- We organize workshops and sessions on various topics in - cybersecurity, including hands-on practice on different platforms. - In 2023, we launched the first in-house Capture The Flag event, - PBCTF, which attracted over 70+ participants. -

-
-
-
- -
-

Events

-
- We organise lots of student centric activities -
-
- -
- -
- -
-

Leads

-
- -
- -
- - ); -} - -const leads = [ - { id: 0, text: "lead 1" }, - { id: 1, text: "lead 2" }, - { id: 2, text: "lead 3" }, -]; - -const eventCard = [ - { - id: 4, - url: '/images/openday.jpg', - textt: "Tech Open Day", - textb: "Our first offline event of the year and it was a huge success✨Get to know about tech societies on campus and how to join them🚀", - }, - { - id: 5, - url: '/images/advaith.jpg', - textt: "Advaith", - textb: "An event full of opportunities, challenges, learning and much more! Be a part of something big, be a part of ADVAITH!", - }, - { - id: 6, - url: '/images/recruit.jpeg', - textt: "Recruitment 2024", - textb: "Recruitment 2024 is here! Join us and be a part of the Point Blank family!🚀", - }, -]; - -const CardComponents = () => { - return ( - <> - {leads.map((lead) => ( -
-

- {lead.text} -

-
- ))} - - ); -}; - -const EventComponent = () => { - return ( - <> - {eventCard.map((ec) => ( -
-
-
-
- -
-
-

{ec.textt}

-

{ec.textb}

-
-
-
-
- ))} - - ); -}; diff --git a/components/leads.tsx b/components/leads.tsx new file mode 100644 index 0000000..f0eac74 --- /dev/null +++ b/components/leads.tsx @@ -0,0 +1,33 @@ +const leads = [ + { id: 0, text: "lead 1" }, + { id: 1, text: "lead 2" }, + { id: 2, text: "lead 3" }, + ]; + + const Leads = () => { + return ( + <> +
+

Leads

+
+ Our Leadership Position are held by the best minds in and across the campus +
+
+
+ {leads.map((lead) => ( +
+

+ {lead.text} +

+
+ ))} +
+ + ); + }; + + export default Leads; + \ No newline at end of file diff --git a/components/magicui/flickering-grid.tsx b/components/magicui/flickering-grid.tsx new file mode 100644 index 0000000..4ef6845 --- /dev/null +++ b/components/magicui/flickering-grid.tsx @@ -0,0 +1,184 @@ +"use client"; + +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; + +interface FlickeringGridProps { + squareSize?: number; + gridGap?: number; + flickerChance?: number; + color?: string; + width?: number; + height?: number; + className?: string; + maxOpacity?: number; +} + +const FlickeringGrid: React.FC = ({ + squareSize = 4, + gridGap = 6, + flickerChance = 0.3, + color = "rgb(0, 0, 0)", + width, + height, + className, + maxOpacity = 0.2, +}) => { + const canvasRef = useRef(null); + const [isInView, setIsInView] = useState(false); + + const memoizedColor = useMemo(() => { + const toRGBA = (color: string) => { + if (typeof window === "undefined") { + return `rgba(0, 0, 0,`; + } + const canvas = document.createElement("canvas"); + canvas.width = canvas.height = 1; + const ctx = canvas.getContext("2d"); + if (!ctx) return "rgba(255, 0, 0,"; + ctx.fillStyle = color; + ctx.fillRect(0, 0, 1, 1); + const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data; + return `rgba(${r}, ${g}, ${b},`; + }; + return toRGBA(color); + }, [color]); + + const setupCanvas = useCallback( + (canvas: HTMLCanvasElement) => { + const canvasWidth = width || canvas.clientWidth; + const canvasHeight = height || canvas.clientHeight; + const dpr = window.devicePixelRatio || 1; + canvas.width = canvasWidth * dpr; + canvas.height = canvasHeight * dpr; + canvas.style.width = `${canvasWidth}px`; + canvas.style.height = `${canvasHeight}px`; + const cols = Math.floor(canvasWidth / (squareSize + gridGap)); + const rows = Math.floor(canvasHeight / (squareSize + gridGap)); + + const squares = new Float32Array(cols * rows); + for (let i = 0; i < squares.length; i++) { + squares[i] = Math.random() * maxOpacity; + } + + return { + width: canvasWidth, + height: canvasHeight, + cols, + rows, + squares, + dpr, + }; + }, + [squareSize, gridGap, width, height, maxOpacity] + ); + + const updateSquares = useCallback( + (squares: Float32Array, deltaTime: number) => { + for (let i = 0; i < squares.length; i++) { + if (Math.random() < flickerChance * deltaTime) { + squares[i] = Math.random() * maxOpacity; + } + } + }, + [flickerChance, maxOpacity] + ); + + const drawGrid = useCallback( + ( + ctx: CanvasRenderingContext2D, + width: number, + height: number, + cols: number, + rows: number, + squares: Float32Array, + dpr: number + ) => { + ctx.clearRect(0, 0, width, height); + ctx.fillStyle = "transparent"; + ctx.fillRect(0, 0, width, height); + + for (let i = 0; i < cols; i++) { + for (let j = 0; j < rows; j++) { + const opacity = squares[i * rows + j]; + ctx.fillStyle = `${memoizedColor}${opacity})`; + ctx.fillRect( + i * (squareSize + gridGap) * dpr, + j * (squareSize + gridGap) * dpr, + squareSize * dpr, + squareSize * dpr + ); + } + } + }, + [memoizedColor, squareSize, gridGap] + ); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + let animationFrameId: number; + let { width, height, cols, rows, squares, dpr } = setupCanvas(canvas); + + let lastTime = 0; + const animate = (time: number) => { + if (!isInView) return; + + const deltaTime = (time - lastTime) / 1000; + lastTime = time; + + updateSquares(squares, deltaTime); + drawGrid(ctx, width * dpr, height * dpr, cols, rows, squares, dpr); + animationFrameId = requestAnimationFrame(animate); + }; + + const handleResize = () => { + ({ width, height, cols, rows, squares, dpr } = setupCanvas(canvas)); + }; + + const observer = new IntersectionObserver( + ([entry]) => { + setIsInView(entry.isIntersecting); + }, + { threshold: 0 } + ); + + observer.observe(canvas); + + window.addEventListener("resize", handleResize); + + if (isInView) { + animationFrameId = requestAnimationFrame(animate); + } + + return () => { + window.removeEventListener("resize", handleResize); + cancelAnimationFrame(animationFrameId); + observer.disconnect(); + }; + }, [setupCanvas, updateSquares, drawGrid, width, height, isInView]); + + return ( + + ); +}; + +export default FlickeringGrid; diff --git a/components/magicui/gradual-spacing.tsx b/components/magicui/gradual-spacing.tsx new file mode 100644 index 0000000..188d148 --- /dev/null +++ b/components/magicui/gradual-spacing.tsx @@ -0,0 +1,44 @@ +"use client"; + +import { AnimatePresence, motion, Variants } from "framer-motion"; + +import { cn } from "@/lib/utils"; + +interface GradualSpacingProps { + text: string; + duration?: number; + delayMultiple?: number; + framerProps?: Variants; + className?: string; +} + +export default function GradualSpacing({ + text, + duration = 0.4, + delayMultiple = 0.04, + framerProps = { + hidden: { opacity: 0, x: -20 }, + visible: { opacity: 1, x: 0 }, + }, + className, +}: GradualSpacingProps) { + return ( +
+ + {text.split("").map((char, i) => ( + + {char === " " ?   : char} + + ))} + +
+ ); +} diff --git a/components/magicui/hyper-text.tsx b/components/magicui/hyper-text.tsx new file mode 100644 index 0000000..e50bc43 --- /dev/null +++ b/components/magicui/hyper-text.tsx @@ -0,0 +1,89 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import { AnimatePresence, motion, Variants } from "framer-motion"; + +import { cn } from "@/lib/utils"; + +interface HyperTextProps { + text: string; + duration?: number; + framerProps?: Variants; + className?: string; + animateOnLoad?: boolean; +} + +const alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); + +const getRandomInt = (max: number) => Math.floor(Math.random() * max); + +export default function HyperText({ + text, + duration = 800, + framerProps = { + initial: { opacity: 0, y: -10 }, + animate: { opacity: 1, y: 0 }, + exit: { opacity: 0, y: 3 }, + }, + className, + animateOnLoad = true, +}: HyperTextProps) { + const [displayText, setDisplayText] = useState(text.split("")); + const [trigger, setTrigger] = useState(false); + const interations = useRef(0); + const isFirstRender = useRef(true); + + const triggerAnimation = () => { + interations.current = 0; + setTrigger(true); + }; + + useEffect(() => { + const interval = setInterval( + () => { + if (!animateOnLoad && isFirstRender.current) { + clearInterval(interval); + isFirstRender.current = false; + return; + } + if (interations.current < text.length) { + setDisplayText((t) => + t.map((l, i) => + l === " " + ? l + : i <= interations.current + ? text[i] + : alphabets[getRandomInt(26)], + ), + ); + interations.current = interations.current + 0.1; + } else { + setTrigger(false); + clearInterval(interval); + } + }, + duration / (text.length * 10), + ); + // Clean up interval on unmount + return () => clearInterval(interval); + }, [text, duration, trigger, animateOnLoad]); + + return ( +
+ + {displayText.map((letter, i) => ( + + {letter.toUpperCase()} + + ))} + +
+ ); +} diff --git a/components/magicui/sparkles-text.tsx b/components/magicui/sparkles-text.tsx new file mode 100644 index 0000000..945daed --- /dev/null +++ b/components/magicui/sparkles-text.tsx @@ -0,0 +1,152 @@ +"use client"; + +import { CSSProperties, ReactElement, useEffect, useState } from "react"; +import { motion } from "framer-motion"; + +import { cn } from "@/lib/utils"; + +interface Sparkle { + id: string; + x: string; + y: string; + color: string; + delay: number; + scale: number; + lifespan: number; +} + +interface SparklesTextProps { + /** + * @default
+ * @type ReactElement + * @description + * The component to be rendered as the text + * */ + as?: ReactElement; + + /** + * @default "" + * @type string + * @description + * The className of the text + */ + className?: string; + + /** + * @required + * @type string + * @description + * The text to be displayed + * */ + text: string; + + /** + * @default 10 + * @type number + * @description + * The count of sparkles + * */ + sparklesCount?: number; + + /** + * @default "{first: '#9E7AFF', second: '#FE8BBB'}" + * @type string + * @description + * The colors of the sparkles + * */ + colors?: { + first: string; + second: string; + }; +} + +const SparklesText: React.FC = ({ + text, + colors = { first: "#9E7AFF", second: "#FE8BBB" }, + className, + sparklesCount = 10, + ...props +}) => { + const [sparkles, setSparkles] = useState([]); + + useEffect(() => { + const generateStar = (): Sparkle => { + const starX = `${Math.random() * 100}%`; + const starY = `${Math.random() * 100}%`; + const color = Math.random() > 0.5 ? colors.first : colors.second; + const delay = Math.random() * 2; + const scale = Math.random() * 1 + 0.3; + const lifespan = Math.random() * 10 + 5; + const id = `${starX}-${starY}-${Date.now()}`; + return { id, x: starX, y: starY, color, delay, scale, lifespan }; + }; + + const initializeStars = () => { + const newSparkles = Array.from({ length: sparklesCount }, generateStar); + setSparkles(newSparkles); + }; + + const updateStars = () => { + setSparkles((currentSparkles) => + currentSparkles.map((star) => { + if (star.lifespan <= 0) { + return generateStar(); + } else { + return { ...star, lifespan: star.lifespan - 0.1 }; + } + }), + ); + }; + + initializeStars(); + const interval = setInterval(updateStars, 100); + + return () => clearInterval(interval); + }, [colors.first, colors.second]); + + return ( +
+ + {sparkles.map((sparkle) => ( + + ))} + {text} + +
+ ); +}; + +const Sparkle: React.FC = ({ id, x, y, color, delay, scale }) => { + return ( + + + + ); +}; + +export default SparklesText; From 159917cb636a4827978a0844a28c3ddf7f294075 Mon Sep 17 00:00:00 2001 From: suvanbanerjee Date: Fri, 16 Aug 2024 23:38:55 +0530 Subject: [PATCH 2/2] Add .env and .env.local to .gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index fd3dbb5..0684900 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,7 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# env +.env +.env.local \ No newline at end of file