diff --git a/src/Header/Boids.tsx b/src/Header/Boids.tsx index dd54b02..2b09ad3 100644 --- a/src/Header/Boids.tsx +++ b/src/Header/Boids.tsx @@ -13,18 +13,21 @@ interface Boid { velocity: Vector } -const BOID_COUNT = 50 const MAX_SPEED = 5 const SEPARATION_DISTANCE = 50 -const ALIGNMENT_RADIUS = 50 +const ALIGNMENT_RADIUS = 60 const COHESION_RADIUS = 50 const BOID_SIZE = 10 +const CURSOR_INFLUENCE_RADIUS = 250 +const CURSOR_INFLUENCE_STRENGTH = 0.5 const Boids: React.FC = () => { const [boids, setBoids] = useState([]) - + const [cursorPosition, setCursorPosition] = useState({ x: 0, y: 0 }) const app = useApp() + const BOID_COUNT = Math.floor(window.innerWidth / 10) // Im not sure if this is a good idea for SUPER high res screens + const stageMargin = 50 useEffect(() => { @@ -80,7 +83,7 @@ const Boids: React.FC = () => { if (total > 0) { steer = multiplyVector(steer, 1 / total) } - return steer + return multiplyVector(steer, 1.02) } const alignment = (boid: Boid, neighbors: Boid[]): Vector => { @@ -90,7 +93,11 @@ const Boids: React.FC = () => { }) if (neighbors.length > 0) { averageVel = multiplyVector(averageVel, 1 / neighbors.length) - return limitVector(averageVel, MAX_SPEED) + const targetVel = addVectors( + multiplyVector(averageVel, 0.1), + multiplyVector(boid.velocity, 0.9) + ) + return limitVector(targetVel, MAX_SPEED) } return boid.velocity } @@ -127,12 +134,35 @@ const Boids: React.FC = () => { const ali = alignment(boid, getNeighbors(boid, ALIGNMENT_RADIUS)) const coh = cohesion(boid, getNeighbors(boid, COHESION_RADIUS)) - // Adjust velocity + // Adjust velocity based on behaviors boid.velocity = addVectors(boid.velocity, sep) boid.velocity = addVectors(boid.velocity, ali) boid.velocity = addVectors(boid.velocity, coh) boid.velocity = limitVector(boid.velocity, MAX_SPEED) + // Calculate distance to cursor + const distanceToCursor = Math.sqrt( + Math.pow(boid.position.x - cursorPosition.x, 2) + + Math.pow(boid.position.y - cursorPosition.y, 2) + ) + + // Adjust velocity based on cursor influence + if (distanceToCursor < CURSOR_INFLUENCE_RADIUS) { + const cursorInfluence = { + x: cursorPosition.x - boid.position.x, + y: cursorPosition.y - boid.position.y, + } + + boid.velocity = addVectors( + boid.velocity, + multiplyVector( + cursorInfluence, + CURSOR_INFLUENCE_STRENGTH / distanceToCursor + ) + ) + boid.velocity = limitVector(boid.velocity, MAX_SPEED) + } + // Update position and apply wrap-around const newPosition = { x: boid.position.x + boid.velocity.x * delta, @@ -183,7 +213,12 @@ const Boids: React.FC = () => { const color = new PIXI.Color(ACCENT_COLOR) return ( - + { + setCursorPosition({ x: e.data.global.x, y: e.data.global.y }) + }} + pointerout={() => setCursorPosition({ x: 0, y: 0 })}> {boids.map((boid, index) => ( { const color = new PIXI.Color(ACCENT_COLOR) return ( - + { + console.log(e.data.global.x, e.data.global.y) + setPlanets([ + ...planets, + { + position: { x: e.data.global.x, y: e.data.global.y }, + velocity: { + x: Math.random() * 1 - 0.5, + y: Math.random() * 1 - 0.5, + }, + mass: Math.random() * 10000000, + }, + ]) + }}> {planets.map((planet, index) => ( { - const possibleStageBackgrounds = [, ] + const [stageWidth, setStageWidth] = useState(window.innerWidth) + const [stageHeight, setStageHeight] = useState(window.innerHeight) + + const ref = useRef(null) + + useEffect(() => { + if (ref.current) { + setStageWidth(ref.current.clientWidth) + setStageHeight(ref.current.clientHeight) + } + }, [ref]) + + const possibleStageBackgrounds = [ + { + stage: , + creator: 'Tomas Maillo', + url: 'https://tomasmaillo.com', + }, + { + stage: , + creator: 'Tomas Maillo', + url: 'https://tomasmaillo.com', + }, + ] const randomStage = useState( possibleStageBackgrounds[ @@ -39,7 +74,7 @@ const Header = () => { )[0] return ( - + { width: '100%', }}> -

+

Project
Share

@@ -69,22 +110,31 @@ const Header = () => { } /> - - {randomStage} - + {randomStage.stage} + +
) } diff --git a/src/Header/Navbar.tsx b/src/Header/Navbar.tsx index 83532e4..9232fe2 100644 --- a/src/Header/Navbar.tsx +++ b/src/Header/Navbar.tsx @@ -3,6 +3,7 @@ import { useState } from 'react' import { styled } from 'styled-components' import { useNavigate } from 'react-router-dom' import { DISCORD_INVITE_LINK } from '../constants' +import WavyText from '../components/WavyText' const StyledNavbar = styled.div` border: 5px solid #7816f4; @@ -108,7 +109,7 @@ const Navbar = () => { href={DISCORD_INVITE_LINK} onMouseEnter={(e: any) => setHoveredItem(e.currentTarget)} onMouseLeave={() => setHoveredItem(null)}> - Discord + ) diff --git a/src/NextMeetup/NextMeetup.tsx b/src/NextMeetup/NextMeetup.tsx index 8235de6..eb303c1 100644 --- a/src/NextMeetup/NextMeetup.tsx +++ b/src/NextMeetup/NextMeetup.tsx @@ -4,6 +4,7 @@ import Dot from '../components/Dot' import BouncingEllipsis from '../components/BouncingEllipsis' import { useEffect, useState } from 'react' import NumberFlipper from './NumberFlipper' +import WavyText from '../components/WavyText' const StyledWrapper = styled.div` position: relative; @@ -26,7 +27,7 @@ const StyledDetail = styled.p` margin: 0; display: flex; align-items: center; - gap: 0.5ch; + gap: 1rem; ` const NextMeetingIsTBC = () => ( @@ -70,11 +71,46 @@ const NextMeeting = () => { return ( - Next meetup - - hrs - min - sec +
+ + +
+
+ {NEXT_MEETUP.location} + + {NEXT_MEETUP.date.toLocaleDateString('en-GB', { + weekday: 'short', + year: 'numeric', + month: 'short', + day: 'numeric', + })} + +
+ {' '} + hrs + min + sec +
+
) diff --git a/src/Pages/About.tsx b/src/Pages/About.tsx new file mode 100644 index 0000000..ed5b53c --- /dev/null +++ b/src/Pages/About.tsx @@ -0,0 +1,125 @@ +import styled from 'styled-components' +import Logo from '../components/Logo' + +const Background = styled.div` + background-color: #f3f3f3; + min-height: 100vh; + padding: 2rem; + + @media (max-width: 768px) { + padding: 16px; + } +` + +const Page = styled.div` + padding: 2rem; + max-width: 600px; + margin: 0rem auto; + padding-top: 2rem; + background-color: white; + border-radius: 10px; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1); + color: black; + + @media (max-width: 600px) { + padding: 24px; + } + margin-bottom: 4rem; +` + +const About = () => { + const user = 'partners' + const domain = 'comp-soc' + const tld = 'com' + + const contactEmail = `${user}@${domain}.${tld}` + + return ( + + +
+ + + {new Date().getFullYear()} +
+

About

+ +

+ Created by four friends on February 16, 2023, Project Share quickly + evolved from casual discussions about personal projects into a vibrant + community of creative minds. It is a place where students showcase and + discuss their projects, exchange ideas, and connect with like-minded + individuals. +

+

+ Project Share reached a milestone in September 2023 when we teamed up + with CompSoc, the Computer Science + Society of the University of Edinburgh. This partnership marked the + beginning of a new chapter as a Special Interest Group (SIG), + amplifying our reach and impact. Together, we're building a dynamic + community where enthusiastic students from every corner of the + university bring their projects to life, share their unique insights, + and connect with industry leaders. +

+ +

Sponsors

+

+ Project Share is formed by a subset of the most talented, proactive + and social tech students at the University of Edinburgh, catering to + those who already possess a solid foundation in tech and are actively + applying their skills. +

+

+ During our fortnightly meetings we bring together developers who are + dedicated to building remarkable projects in their spare time. They + showcase their progress on projects and hear updates from others, + giving members a chance to exchange valuable insights and lessons + learned. +

+

+ In Project Share’s first semester of operation, we created a community + of 250 members and followed the development of more than 40 projects. + These projects range from custom-built online delivery systems, 3D + websites, compilers, to AI chess engines. Many members have secured + part-time jobs and summer internships through contacts made at Project + Share. +

+ +

+ Looking ahead, we aim to broaden our presence to include the talent of + electrical and mechanical engineering students into our community, in + combination with running more events like hackathons. +

+

+ Project Share is actively seeking the support of sponsors to reach our + future goals. We are looking for industry speakers to enrich our + sessions, as well as sponsors aiming to increase their brand + visibility within this Special Interest Group (SIG). For brands + seeking to connect with top-tier, proactive talent, Project Share + offers the ideal platform. +

+

+ If you are interested in sponsoring Project Share, please contact us + at through our parent society CompSoc at{' '} + {contactEmail}. +

+

Contact

+ + Feedback Form + +
+
+ ) +} + +export default About diff --git a/src/Pages/Home.tsx b/src/Pages/Home.tsx index d0a665a..d287d32 100644 --- a/src/Pages/Home.tsx +++ b/src/Pages/Home.tsx @@ -42,13 +42,13 @@ const Home = () => { }}>
diff --git a/src/Pages/Team.tsx b/src/Pages/Team.tsx index 594ec9d..6afef1c 100644 --- a/src/Pages/Team.tsx +++ b/src/Pages/Team.tsx @@ -1,30 +1,22 @@ -import BackLink from '../components/BackLink' import SketchLines from '../components/SketchLines' function Team() { return ( - <> - /team - - -
- - 🚧 Coming soon...
- Even sooner if you make a{' '} - - PR - -
-
- +
+ + 🚧 Coming soon...
+ Even sooner if you make a{' '} + PR +
+
) } diff --git a/src/components/ScrollText.tsx b/src/components/ScrollText.tsx index 5c0634b..fa04dc5 100644 --- a/src/components/ScrollText.tsx +++ b/src/components/ScrollText.tsx @@ -17,7 +17,10 @@ const TextContainer = styled.span` overflow: hidden; ` -const StaticText = styled(motion.span)`` +const StaticText = styled(motion.span)` + transition: 0.2s; + color: #7816f4; +` interface ContentLineProps { content: string diff --git a/src/components/WavyText.tsx b/src/components/WavyText.tsx new file mode 100644 index 0000000..50e12f0 --- /dev/null +++ b/src/components/WavyText.tsx @@ -0,0 +1,52 @@ +import { useState, useEffect } from 'react' +import styled, { keyframes } from 'styled-components' + +const wavyAnimation = keyframes` + 40% { + color: black; + opacity: 1; + transform: translateY(0px) scale(1); + } + 50% { + color: #7816f4; + opacity: 0.7; + transform: translateY(-3px) scale(0.9); + } + + 60% { + color: black; + opacity: 1; + transform: translateY(0px) scale(1); + } + ` + +const WavySpan = styled.span<{ delay: number }>` + display: inline-block; + animation: ${wavyAnimation} 3s ease infinite; + animation-delay: ${({ delay }) => delay}ms; +` + +const WavyText = ({ text, ...props }: { text: string }) => { + const [letters, setLetters] = useState([]) + + useEffect(() => { + setLetters(text.split('')) + }, [text]) + + return ( + + {letters.map((letter, index) => ( + + {letter} + + ))} + + ) +} + +export default WavyText diff --git a/src/constants.ts b/src/constants.ts index 5ef3dbb..03fa19e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -13,8 +13,8 @@ export interface MeetupDetails { export const NEXT_MEETUP: MeetupDetails | undefined = { title: 'Project Share!', - date: new Date('2023-12-16T15:55:00'), - location: 'AT 2.05', + date: new Date('2024-01-24T15:00:00'), + location: 'AT 2.11', description: 'Bring your laptop!', } diff --git a/src/main.tsx b/src/main.tsx index ec57028..87d4201 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -10,15 +10,17 @@ import Projects from './Pages/Projects' import Components from './Pages/Components' import ScrollToTop from './components/ScrollToTop' import Navbar from './Header/Navbar' +import About from './Pages/About' ReactDOM.render( - + } /> } /> + } /> } /> } />