diff --git a/package-lock.json b/package-lock.json index f94a3bf..6325efa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "react-dom": "^18.3.1", "react-i18next": "^15.0.2", "react-icons": "^5.3.0", - "react-router-dom": "^6.23.1", + "react-router-dom": "^6.30.0", "react-scripts": "5.0.1", "stream": "^0.0.3", "typescript": "^4.9.5", @@ -5313,9 +5313,10 @@ "peer": true }, "node_modules/@remix-run/router": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", - "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -20020,11 +20021,12 @@ } }, "node_modules/react-router": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", - "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", + "version": "6.30.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.0.tgz", + "integrity": "sha512-D3X8FyH9nBcTSHGdEKurK7r8OYE1kKFn3d/CF+CoxbSHkxU7o37+Uh7eAHRXr6k2tSExXYO++07PeXJtA/dEhQ==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.16.1" + "@remix-run/router": "1.23.0" }, "engines": { "node": ">=14.0.0" @@ -20034,12 +20036,13 @@ } }, "node_modules/react-router-dom": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", - "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", + "version": "6.30.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.0.tgz", + "integrity": "sha512-x30B78HV5tFk8ex0ITwzC9TTZMua4jGyA9IUlH1JLQYQTFyxr/ZxwOJq7evg1JX1qGVUcvhsmQSKdPncQrjTgA==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.16.1", - "react-router": "6.23.1" + "@remix-run/router": "1.23.0", + "react-router": "6.30.0" }, "engines": { "node": ">=14.0.0" @@ -28241,9 +28244,9 @@ "peer": true }, "@remix-run/router": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", - "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==" + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==" }, "@rnx-kit/chromium-edge-launcher": { "version": "1.0.0", @@ -38732,20 +38735,20 @@ "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" }, "react-router": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", - "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", + "version": "6.30.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.0.tgz", + "integrity": "sha512-D3X8FyH9nBcTSHGdEKurK7r8OYE1kKFn3d/CF+CoxbSHkxU7o37+Uh7eAHRXr6k2tSExXYO++07PeXJtA/dEhQ==", "requires": { - "@remix-run/router": "1.16.1" + "@remix-run/router": "1.23.0" } }, "react-router-dom": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", - "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", + "version": "6.30.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.0.tgz", + "integrity": "sha512-x30B78HV5tFk8ex0ITwzC9TTZMua4jGyA9IUlH1JLQYQTFyxr/ZxwOJq7evg1JX1qGVUcvhsmQSKdPncQrjTgA==", "requires": { - "@remix-run/router": "1.16.1", - "react-router": "6.23.1" + "@remix-run/router": "1.23.0", + "react-router": "6.30.0" } }, "react-scripts": { diff --git a/package.json b/package.json index 439d38b..f7c95f0 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "react-dom": "^18.3.1", "react-i18next": "^15.0.2", "react-icons": "^5.3.0", - "react-router-dom": "^6.23.1", + "react-router-dom": "^6.30.0", "react-scripts": "5.0.1", "stream": "^0.0.3", "typescript": "^4.9.5", diff --git a/src/App.tsx b/src/App.tsx index 222b465..4ba6197 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,6 +8,7 @@ import Minutes from './pages/Minutes/Minutes'; import Volunteer from './pages/Volunteer/Volunteer'; import Blog from './pages/Blog/Blog'; import Events from './pages/Events/Events'; +import Sponsors from './pages/Sponsors/sponsors' export function getWindowDimensions() { const { innerWidth: width, innerHeight: height } = window; @@ -24,6 +25,7 @@ const App: React.FC = () => { { name: 'Volunteer', url: '/volunteer' }, { name: 'Minutes', url: '/minutes' }, { name: 'About', url: '/about' }, + { name: 'Sponsors', url: '/sponsors' }, ]; const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions()); @@ -34,6 +36,7 @@ const App: React.FC = () => { + diff --git a/src/images/sponsors/cse-cst.webp b/src/images/sponsors/cse-cst.webp new file mode 100644 index 0000000..667ae11 Binary files /dev/null and b/src/images/sponsors/cse-cst.webp differ diff --git a/src/images/sponsors/nokia.webp b/src/images/sponsors/nokia.webp new file mode 100644 index 0000000..eb61e84 Binary files /dev/null and b/src/images/sponsors/nokia.webp differ diff --git a/src/images/sponsors/placeholder.webp b/src/images/sponsors/placeholder.webp new file mode 100644 index 0000000..dd97240 Binary files /dev/null and b/src/images/sponsors/placeholder.webp differ diff --git a/src/pages/Sponsors/sponsors-carousel-buttons.css b/src/pages/Sponsors/sponsors-carousel-buttons.css new file mode 100644 index 0000000..119852b --- /dev/null +++ b/src/pages/Sponsors/sponsors-carousel-buttons.css @@ -0,0 +1,21 @@ +.sponsors-buttoncontainer{ + font-family: 'Intervogue Soft'; + display: flex; + flex-direction: row-reverse; + justify-content: center; + padding: 3% 0; +} + +.sponsors-buttons{ + background-color: transparent; + outline: none; + border: none; + display: flex; + flex-direction: column; + color: rgba(0, 0, 0, 0); +} + +button svg{ + width: 3em; + height: 3em; +} \ No newline at end of file diff --git a/src/pages/Sponsors/sponsors-carousel.buttons.tsx b/src/pages/Sponsors/sponsors-carousel.buttons.tsx new file mode 100644 index 0000000..dab9fe0 --- /dev/null +++ b/src/pages/Sponsors/sponsors-carousel.buttons.tsx @@ -0,0 +1,24 @@ +import React, { useRef, useState, useEffect} from "react"; +import './sponsors-carousel-buttons.css'; + +interface CarouselButtonProps{ + changesponsor: (direction: string) => void; +} + +const CarouselButtons: React.FC = ({changesponsor}) => { + return( +
+ + +
+ ); +}; + + +export default CarouselButtons; \ No newline at end of file diff --git a/src/pages/Sponsors/sponsors-carousel.css b/src/pages/Sponsors/sponsors-carousel.css new file mode 100644 index 0000000..dd4a02c --- /dev/null +++ b/src/pages/Sponsors/sponsors-carousel.css @@ -0,0 +1,107 @@ +:root { + --easing: cubic-bezier(0.18, 0.89, 0.32, 1.27); + --duration: 0.5s; +} +.wheel { + width: 65vmin; + height: 65vmin; + transition: transform var(--duration) var(--easing); + position: relative; + top: 0%; + left: 0%; + margin: 0; + background-color: transparent; +} +.slide { + width: 40vw; + height: 0vw; + max-width: 600px; + max-height: 600px; + border-radius: 50%; + cursor: pointer; + transition: transform var(--duration) var(--easing); + border: 0.3vmin solid white; + position: absolute; + box-sizing: border-box; +} +.slide img { + border-radius: 50%; + width: 100%; + height: 100%; + object-fit: cover; + pointer-events: none; + position: absolute; + top: 0; + left: 0; +} +.slide img { + user-select: none; +} + +.slide.active-mobile { + border-width: 1.3vmin; + /* height: 20vw; + width: 20vw; */ + /*I want to make the highlighted one bigger - Low priority task*/ +} +.slide.active-landscape{ + border-width: 1vmin; + height: 20vw; + width: 20vw; +} +.wheel-border{ + border: 3px #326491 dashed; + margin: 0; + animation: spin 30s linear infinite; + background-color: transparent; +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +@media only screen and (orientation: portrait){ + .container{ + width: 100%; + height: 100%; + overflow: hidden; + position: absolute; + transform: translateX(10%); + } + .wheel{ + width: 100vw; + height: 100vw; + border-radius: 50%; + } + .wheel-border{ + height: inherit; + width: inherit; + border-radius: 50%; + background-color: transparent; + } +} +@media only screen and (orientation: landscape){ + .container{ + width: 100%; + height: 100%; + overflow: hidden; + rotate: 90deg; + align-self: stretch; + } + .wheel{ + width: 100vh; + height: 100vh; + border-radius: 50%; + rotate: -90deg; + + } + .wheel-border{ + height: inherit; + width: inherit; + border-radius: 50%; + background-color: transparent; + } +} \ No newline at end of file diff --git a/src/pages/Sponsors/sponsors-carousel.tsx b/src/pages/Sponsors/sponsors-carousel.tsx new file mode 100644 index 0000000..b030175 --- /dev/null +++ b/src/pages/Sponsors/sponsors-carousel.tsx @@ -0,0 +1,168 @@ +import React, { useRef, useState, useEffect} from "react"; +import './sponsors-carousel.css'; + +interface CircularCarouselProps { + flexDirection: string; + getCurrentSponsor: (value: any) => void; + images: any[]; + carouselIndex: number; +} + +const SponsorsCircularCarousel: React.FC = ({flexDirection, getCurrentSponsor, images, carouselIndex}) => { + + const wheelRef = useRef(null); + const initialSlidesState = images.map((slide, index) => ({ + coords: { + x: 0, + y: 0 + }, + theta: 0, + index: index + 1, + image: slide.frontImage, + name: slide.name, + description: slide.description, + type: slide.type + })); + + const numSlides = images.length; + const angle = 360 / numSlides; + + const [slides, setSlides] = useState(initialSlidesState); + const [activeSlide, setActiveSlide] = useState(slides[0]); + const [wheelWidth, setWheelWidth] = useState(0); + const [center, setCenter] = useState({ x: 0, y: 0 }); + const [rotate, setRotate] = useState(0); + + const getInitialPositions = () => { + const center = { + x: parseFloat(getComputedStyle(wheelRef.current.parentNode).width) / 2 - parseFloat(getComputedStyle(wheelRef.current).width) /2, + y: parseFloat(getComputedStyle(wheelRef.current.parentNode).height) / 2 - parseFloat(getComputedStyle(wheelRef.current).height) /2 + }; + setCenter(center); + setWheelWidth(parseFloat(getComputedStyle(wheelRef.current.parentNode).width)); + }; + + useEffect(() => { + if (!wheelRef.current) { + return; + } + getInitialPositions(); + window.addEventListener("resize", getInitialPositions); + return () => window.removeEventListener("resize", getInitialPositions); + }, []); + + useEffect(() => { + if (!wheelWidth) { + return; + } + + setActiveSlide(slides[carouselIndex]); + setRotate(angle * carouselIndex); + + let positionedSlides = slides.map((slide, index) => { + + // Calculate angle increment based on total slides, + //we're doing this in radians for simplification + const angleIncrement = (2 * Math.PI) / slides.length; + var newTheta = angleIncrement * index; + + //This is done so the middle one is highlighted and not the top one + if(flexDirection === 'row'){ + newTheta = angleIncrement * (index - 1); + } + // Calculate angle for current slide + + const wheelRadius = wheelWidth / 2; + var y = -wheelRadius * Math.cos(newTheta); // Calculate x-coordinatewheel + var x = -wheelRadius * Math.sin(newTheta); // Calculate y-coordinate + + return { + ...slide, + coords: { x: y, y: x } + }; + }); + + setSlides(positionedSlides); + }, [carouselIndex, wheelWidth, flexDirection]); + + const handleSlideClick = (e: any) => { + const nextIndex = parseFloat(e.currentTarget.dataset.index); + const currentIndex = activeSlide.index; + + setActiveSlide(slides[nextIndex - 1]); + getCurrentSponsor(slides[nextIndex - 1]) + + let numOfRotations = nextIndex - currentIndex; + + if (numOfRotations < -numSlides / 2) { + numOfRotations = numOfRotations + numSlides; + } + + if (numOfRotations > numSlides / 2) { + numOfRotations = numOfRotations - numSlides; + } + + setRotate((prevRotate) => prevRotate + angle * numOfRotations); + }; + + if(flexDirection === 'column'){ + return ( +
+
+
+ {slides && + slides.map((slide, index) => { + return ( +
{handleSlideClick(e);}} + key={index} + ref={wheelRef} + className={`slide ${slide.index === activeSlide.index ? 'active-mobile' : ''}`} + data-index={index + 1} + style={{ + top: center.x + slide.coords.x, + left: center.y + slide.coords.y, + transform: `rotate(${-rotate}deg)` + }} + > + cssa member +
+ ); + })} +
+ +
+ ); + } + + return ( +
+
+
+ {slides && + slides.map((slide, index) => { + return ( +
+ cssa member +
+ ); + })} +
+ +
+ ); +}; + +export default SponsorsCircularCarousel; \ No newline at end of file diff --git a/src/pages/Sponsors/sponsors.css b/src/pages/Sponsors/sponsors.css new file mode 100644 index 0000000..4bee22c --- /dev/null +++ b/src/pages/Sponsors/sponsors.css @@ -0,0 +1,44 @@ +.sponsors-body{ + height: 92vh; + width: 100vw; + display: flex; + box-sizing: border-box; + overflow: hidden; + top: 8vh; + text-align: center; +} + +.sponsors-leftside{ + height: 100%; + width: 50%; + display: flex; + justify-content: flex-start; + position: relative; +} + +.sponsors-rightside{ + height: 100%; + width: 50%; + display: flex; + flex-direction: column; + justify-content: center; +} + +.sponsors-type{ + justify-content: center; +} + +.sponsors-name{ + justify-content: center; + padding: 0 20%; +} + +.sponsors-desc{ + justify-content: center; +} + +/* +.container{ + +} +*/ \ No newline at end of file diff --git a/src/pages/Sponsors/sponsors.tsx b/src/pages/Sponsors/sponsors.tsx new file mode 100644 index 0000000..e2a1c4f --- /dev/null +++ b/src/pages/Sponsors/sponsors.tsx @@ -0,0 +1,67 @@ +//import stuff errmmmmm idk +//am i in the kitchen +import SponsorsCircularCarousel from './sponsors-carousel'; +import CarouselButtonProps from './sponsors-carousel.buttons'; +import { sponsorsInfo } from '../../resources/sponsorsImagesInfo'; +import Navbar from "../../components/Navbar"; +import { getWindowDimensions } from "../Home/Home"; +import BinaryBackground from "../Home/BinaryBackground"; +import React, { useRef, useState } from "react"; +import './sponsors.css' + +const Sponsors: React.FC = () =>{ + const sponsortypes = ["type", "type", "type"]; + const sponsornames = ["Nokia", "Communications Security Establishment (CSE) Canada", "Sponsor Us!"]; + const sponsordescs = ["yap", "yap", "plssss"]; + + const [currentSponsor, setCurrentSponsor] = useState(sponsorsInfo[0]); + const [currentindex, setIndex] = useState(0); + + const changesponsor = (direction: string) => { + + // Handle carousel navigation logic (forward/backward) + let index = currentindex; + + if (direction === "fwd"){ + index++; + } + else if (direction === "back"){ + index--; + } + + if (index === sponsorsInfo.length){ + index = 0; + } + else if (index < 0){ + index = sponsorsInfo.length - 1; + } + + setCurrentSponsor(sponsorsInfo[index]);; + + setIndex(index); + } + + return( +
+ + +
+ +
+
+
+

{currentSponsor.type}

+
+
+

{currentSponsor.name}

+
+
+

{currentSponsor.description}

+
+ +
+
+ ) +} + +export default Sponsors; \ No newline at end of file diff --git a/src/resources/sponsorsImagesInfo.ts b/src/resources/sponsorsImagesInfo.ts new file mode 100644 index 0000000..6614fcd --- /dev/null +++ b/src/resources/sponsorsImagesInfo.ts @@ -0,0 +1,31 @@ +import cse from '../images/sponsors/cse-cst.webp'; +import nokia from '../images/sponsors/nokia.webp'; +import placeholder from '../images/sponsors/placeholder.webp'; + +export interface Sponsor { + name: string; + type: string; + description: string; + frontImage: string; +} + +export const sponsorsInfo: Sponsor[] = [ + { + name: "Nokia", + type: "sponsor type", + description: "blalablablablabalb", + frontImage: nokia + }, + { + name: "Communications Security Establishment (CSE) Canada", + type: "sponsor type 2", + description: "bababbababab 2", + frontImage: cse + }, + { + name: "Sponsor us!", + type: "", + description: "PLEASEPLEASEPLEASEPLEASEPLASE", + frontImage: placeholder + }, +] \ No newline at end of file