11 Commits

Author SHA1 Message Date
4695dea933 add waterfall pic wall 2023-09-26 19:50:08 -05:00
086b2087b1 Merge branch 'main' into feat/waterfallpic 2023-09-26 19:42:34 -05:00
84e7889653 add waterfall pic wall 2023-09-26 19:42:02 -05:00
a883ebe2ef modify test 2023-09-26 19:25:53 -05:00
43d66d50ae feat: add water fall pic 2023-09-22 21:57:45 -05:00
2300d2bbf3 fix color 2023-09-19 20:53:38 -05:00
118c39afb8 error fixed 2023-09-19 20:43:26 -05:00
b08e0e9b4e updated projects 2023-09-19 20:29:24 -05:00
a859b2824f feat: add projects 2023-09-19 15:01:22 -05:00
a6b5fc79fa feat: add projects 2023-09-19 14:53:01 -05:00
858b9e0f27 Merge pull request 'add .gitignore' (#1) from feature/add-gitignore into main
Reviewed-on: #1
2023-09-17 02:37:50 +00:00
24 changed files with 2108 additions and 22 deletions

1622
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"ahooks": "^3.7.8", "ahooks": "^3.7.8",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"antd": "^5.9.2",
"axios": "^1.3.2", "axios": "^1.3.2",
"hamburger-react": "^2.5.0", "hamburger-react": "^2.5.0",
"nodemon": "^2.0.20", "nodemon": "^2.0.20",

View File

@ -0,0 +1,80 @@
import fenrir from "../pics/fenrir.jpg";
import roslund from "../pics/roslund.jpg";
import goliath from "../pics/goliath.jpg";
import icarus from "../pics/icarus.jpg";
import mach2 from "../pics/mach2.jpg";
import osiris from "../pics/osiris.jpg";
import Modulus from "../pics/modulus.jpg";
import Roomba from "../pics/roomba.jpg";
import MRK from "../pics/fancypants.jpg";
import Mongol from "../pics/mongol.jpg";
import ma from "../pics/matchlock.jpg";
const projects = {
active: [
{
title: "⏩ Goliath",
content: `Golaith is designed to effectively compete in the annual MRDC. Goliath is based on a relatively simple drive base consisting of a basic square steel frame, 2 large drive wheels powered by 3HP Ampflow Magmotors and two steel ball casters. The simplicity of this design makes Goliath a very durable and reliable robot that is able to easily withstand encounters with other robots and course obstacles. In addition, this robot was designed such that the center of mass is low to the ground and as close as possible to the drive wheels which, when coupled with its powerful drivetrain, allows it to easily climb and descend relatively steep inclines as well as move very slowly and precisely when necessary. Overall, these design features enable Goliath to reliably perform many competition tasks with minimal impact from any obstacles encountered along the way.`,
img: goliath,
sub: "💪"
},
{
title: "⏩ Modulus",
content: `Modulus uses a crab drive propulsion system and is primarily based off the FIRST robotics kit. A crab drive system consists of a 4 wheel base where each wheel can rotate independently without turning the entire body. This can be very useful for competitions where mobility is important such as MRDC.`,
img: Modulus,
sub: "🧠"
},
{
title: "⏩ Roslund",
content: `Roslund is a simple frame robot with mechanum drive. Mechanum wheels have rollers at a 45° angle to the wheel plane, which allows the robot to have omnidirectional movement. Roslund was the winner of MRDC in 2010 and 2011. Roslund was also awarded the best design award by Grant Imahara (from the Mythbusters) a couple years back.`,
img: roslund,
sub: "✨"
}
],
inactive: [
{
title: "⏩ Fenrir",
content: `Fenrir is a two-wheeled gravity-drive robot. Fenrir's unique design makes it a very fast and agile robot, but also an interesting challenge to control. You can find the current controller code at our github repo: https://github.com/illinoistechrobotics/fenrir.`,
img: fenrir,
sub: "🔜"
},
{
title: "⏩ C-Force",
content: `C-Force is our award winning pumpkin launcher which uses centripetal force to launch pumpkins. A 5HP, 3 phase industrial motor and variable frequency drive is used to spin up the launching arm to approximately 200 RPM and then a second custom designed control system releases the pumpkin on command from a laptop connected via WiFi. There is an optical sensor on the launcher providing input to the controller to signal when the arm is at the proper angle to release the pumpkin. This allows the launcher to consistently throw the pumpkin at the ideal launch angle to acheive the maximum possible distance.`,
img: mach2,
sub: "🔜"
},
{
title: "⏩ Icarus",
content: `Icarus is a quadcopter (a four-rotor helicopter) that is able to lift more weight and is more agile than a standard helicopter. But these benefits come at a cost of stability and require many electronic sensors to maintain stable flight. We are currently working on an RC car to tether to Icarus toact as a manipulator. This way it can pull Icarus close to balls without blowing them away and pick them up. The manipulator will be used during competitions such as MRDC.`,
img: icarus,
sub: "🪁"
},
{
title: "⏩ Osiris",
content: `A full body spinner prototype design with a hexagonal pyramid shell. Used MPU-6050 Gyroscope/Accelerameter package, Yumo/Omron rotary encoders, and I2C communication between Arduino Unos for PID and translational drift control. Required a soldered interface board between Open Source Motor Controller (OSMC) and Arduino Mega consisting of a L7805 voltage regulator, line driver, and optocoupler packages to provide current and signal isolation. Each of 3 Ampflow magmotors has a peak of 4.6 horsepower and draws 150 Amps at full load. Future improvements include fabricating metal body and shell, and integrating the OSMC interface board into a PCB with motor controller components that can operate at 48 V.`,
img: osiris,
sub: "🤖"
},
{
title: '⏩ Roombotics',
content: `Our club received a donation of 30 Roombas. We have decided to build a robotic swarm using them. This swarm will be able to communicate with each other to work together to fulfill a task. Possible tasks that we have thought of include mapping, search and rescue, and playing sports. We are currently using Arduinos to control the Roombas through their on-board commands.`,
img: Roomba,
sub: "🧼"
},
{
title: '⏩ Fancy Pants',
content: `Fancy Pants is a lower extremity exoskeleton and is one of the older projects at ITR. It is currently undergoing a significant redesign with the goals of increasing precision, comfort and safety. Although this exo needs a lot of work before it will be hurling someone 15 feet into the air safely, it has potential for greatness.`,
img: MRK,
sub: "🦾"
},
{
title: '⏩ Mongol',
content: `Mongol is designed to compete in Mech-Warfare. In Mech-Warfare, all robots must walk on 2 or 4 legs as a means of propulsion. Each robot is also equipped with airsoft cannons and impact sensor plates. Each robot is given a certain number of 'hits' and is pitted against competitors in model cityscape to where the object of the competition is to reduce each opponents hits to zero before falling to zero themselves. Meanwhile, though able to be remote controlled, each robot's pilot cannot view the robot directly and must control the robot with visual information coming only from a wireless camera on the robot itself. Mongol was designed entirely in SolidWorks. For more information about Mech-Warfare visit mech-warfare.com`,
img: Mongol,
sub: "🖐️"
}
],
};
export default projects;

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
src/assets/pics/fenrir.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

BIN
src/assets/pics/goliath.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
src/assets/pics/icarus.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
src/assets/pics/mach2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

BIN
src/assets/pics/modulus.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
src/assets/pics/mongol.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

BIN
src/assets/pics/osiris.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

BIN
src/assets/pics/roomba.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
src/assets/pics/roslund.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

View File

@ -136,6 +136,21 @@
} }
} }
@media screen and (max-width: 650px) {
.about__content__main__container {
width: 90vw;
}
.about__content__blocks_block {
width: 90vw;
}
.about__content__main__container span,
.about__content__blocks_block span {
font-size: 18px;
}
}
@keyframes fade { @keyframes fade {
0% { 0% {
opacity: 0; opacity: 0;

View File

@ -1,19 +1,26 @@
#container { .c {
opacity: 100%; opacity: 100%;
-webkit-animation: fade 0.9s ease-in; -webkit-animation: fade 0.9s ease-in;
-moz-animation: fade 0.9s ease-in; -moz-animation: fade 0.9s ease-in;
-ms-animation: fade 0.9s ease-in; -ms-animation: fade 0.9s ease-in;
-o-animation: fade 0.9s ease-in; -o-animation: fade 0.9s ease-in;
animation: fade 0.9s ease-in; animation: fade 0.9s ease-in;
background-color: black; background: linear-gradient(#3b3b3b, #1a1a1a);
position: relative;
margin: 0px;
padding: 0px;
width: 100vw;
} }
.error { .error {
background-color: #232323; background-color: #3d3d3d;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
display: flex; display: flex;
height: calc(100vh - 101px); height: calc(100vh - 101px);
position: relative;
top: 0;
left: 0;
} }
.error__photo { margin: 0px; .error__photo { margin: 0px;

View File

@ -192,6 +192,7 @@ li a:hover {
.hamburger-react { .hamburger-react {
color: #fff; color: #fff;
display: block; display: block;
margin-right: 10px;
} }
.navbar__hamburger { .navbar__hamburger {
display: flex; display: flex;

View File

@ -0,0 +1,175 @@
@font-face {
font-family: itrFont;
src: url(../font/LeagueSpartan-ExtraBold.ttf);
}
@font-face {
font-family: itrFontMedium;
src: url(../font/LeagueSpartan-Medium.ttf);
}
.project {
background-color: #232323;
width: 100%;
min-height: 100vh;
height: auto;
opacity: 100%;
overflow-x: hidden;
display: flex;
-webkit-animation: fade 0.9s ease-in;
-moz-animation: fade 0.9s ease-in;
-ms-animation: fade 0.9s ease-in;
-o-animation: fade 0.9s ease-in;
animation: fade 0.9s ease-in;
background: linear-gradient(#3b3b3b, #1a1a1a);
}
.projects_wrap {
flex-wrap: wrap;
padding: 24px;
margin-left: 20px;
display: flex;
flex-direction: row;
justify-content: start;
}
.projects__title {
margin: 20px 0 20px 20px;
font-family: itrFontMedium;
color: #fff;
text-align: center;
}
.project__content {
position: relative;
width: 100%;
height: auto;
overflow: hidden;
}
.project__content__main {
width: 100vw;
height: auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-top: 24px;
}
.project__content__main__container {
padding: 20px;
border-radius: 10px;
background-color: rgb(66, 66, 66);
box-sizing: border-box;
display: flex;
flex-direction: column;
transition: 0.3s;
cursor: default;
overflow: hidden;
margin: 0 16px 16px 0;
}
.project_item_content {
flex-grow: 1;
overflow: scroll;
}
.project_item_content_image {
border-radius: 10px;
transition: .1s;
}
.project_item_content_image:hover {
border-radius: 0px;
}
.project__content__main__container h1,
.project__content__blocks_block h1 {
color: white;
opacity: 100%;
font-size: 40px;
font-weight: bold;
font-family: "itrFont";
padding: 10px;
}
.project__content__main__container span,
.project__content__blocks_block span {
color: rgb(238, 238, 238);
opacity: 100%;
font-size: 18px;
font-family: itrFontMedium;
padding: 10px;
line-height: 20px;
border-radius: 10px;
display: block;
overflow: hidden;
width: 100%;
box-sizing: border-box;
}
.project__content__blocks_block span {
margin-bottom: 30px;
}
.project__content__blocks {
margin-top: 6vh;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: auto;
margin-right: calc(-1 * (100vw - 100%));
}
.project__content__blocks_block {
position: relative;
border-radius: 10px;
background-color: rgb(66, 66, 66);
width: 25vw;
margin-left: 3vw;
margin-right: 3vw;
min-height: 38vh;
height: auto;
padding: 10px;
display: flex;
flex-direction: column;
transition: 0.3s;
cursor: pointer;
}
.project__content__blocks_block p {
position: absolute;
bottom: 0;
color: rgb(136, 136, 136);
opacity: 100%;
font-size: 20px;
font-family: itrFontMedium;
padding: 10px;
line-height: 32px;
border-radius: 10px;
}
.project__content__blocks_block:hover,
.project__content__main__container:hover {
background-color: #666666;
}
@media screen and (max-width: 1550px) {
.project__content__blocks {
flex-direction: column;
}
.project__content__blocks_block {
margin-bottom: 6vh;
width: 80vw;
}
.project__content__blocks_block h1 {
font-size: 35px;
}
}
@keyframes fade {
0% {
opacity: 0;
}
}

View File

@ -0,0 +1,7 @@
.waterfallContainer {
display: flex;
flex-wrap: wrap;
.waterfallItem {
margin: 3px;
}
}

View File

@ -0,0 +1,21 @@
import { useContainer } from "unstated-next";
import DropdownContainer from "../components/DropdownContainer";
import GlobalStore from "../store/global";
import NavBar from "../components/NavBar";
import Footer from "../components/Footer";
const AppOuter = ({ children }) => {
const { isHamburger, setIsHamburger } = useContainer(GlobalStore);
return (
<div className="container">
{isHamburger ? (
<DropdownContainer hamburgerToggle={setIsHamburger} />
) : null}
<div style={{ marginTop: 70 }}>{children}</div>
<NavBar hamburgerToggle={setIsHamburger}></NavBar>
<Footer></Footer>
</div>
);
};
export default AppOuter;

View File

@ -1,22 +1,41 @@
import React, { Component } from "react"; import React, { useEffect, useMemo } from "react";
import backgroundVideo from "../assets/video.mp4"; import "../assets/stylesheets/project.scss";
import "../assets/stylesheets/home.scss"; import { useContainer } from "unstated-next";
import GlobalStore from "../store/global";
import projects from "../assets/data/projects";
import WaterfallPosition from "./Waterfall";
export default class Projects extends Component { const Project = () => {
render() { useEffect(() => {
window.scrollTo(0, 0);
}, []);
const { bodySize } = useContainer(GlobalStore);
const count = useMemo(() => {
if (bodySize.width > 850) {
return 3;
}
if (bodySize.width > 650) {
return 2;
}
return 1;
}, [bodySize]);
return ( return (
<div className="home"> <div className="project">
<video autoPlay loop muted className="home__video"> <div className="project__content">
<source src={backgroundVideo} type="video/mp4" /> <div className="project__content__main">
</video> <div>
<div className="home__content"> <h1 className="projects__title">Active Projects</h1>
<label className="home__content__title"> <WaterfallPosition columnNumber={count} list={projects.active} />
ILLINOIS TECH </div>
<br /> <div>
ROBOTICS <h1 className="projects__title">Retired/Inactive Projects</h1>
</label> <WaterfallPosition columnNumber={count} list={projects.inactive} />
</div>
</div>
{/* <WaterfallPositionDemo /> */}
</div> </div>
</div> </div>
); );
} };
} export default Project;

120
src/components/Waterfall.js Normal file
View File

@ -0,0 +1,120 @@
import { useSize } from "ahooks";
import React, { useRef, useEffect, useState } from "react";
import "../assets/stylesheets/waterfall.scss";
import { Image } from "antd";
const WaterfallItem = ({ data, onLoad }) => {
const ref = useRef();
const size = useSize(ref);
const sizeRef = useRef({});
useEffect(() => {
sizeRef.current.size = size;
}, [size]);
return (
<div className="waterfallItem" ref={ref}>
<div className="project__content__main__container">
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
<h3
style={{
fontFamily: "itrFontMedium",
fontSize: "25px",
color: "#fff",
marginBottom: 12,
}}
>
{data.title}
</h3>
<h3
style={{
fontFamily: "itrFontMedium",
fontSize: "25px",
color: "#fff",
marginBottom: 12,
}}
>
{data.sub}
</h3>
</div>
<div className="project_item_content">
<Image
onLoad={() => {
setTimeout(() => {
onLoad(sizeRef.current.size);
}, 500);
}}
onError={() =>
setTimeout(() => {
onLoad(sizeRef.current.size);
}, 500)
}
width={"100%"}
src={data.img}
/>
<span>{data.content}</span>
</div>
</div>
</div>
);
};
const WaterfallPosition = ({ columnNumber, list }) => {
const stateRef = useRef({
heights: [],
loadNum: 0,
});
const onload = (index, height) => {
stateRef.current.heights[index] = height;
stateRef.current.loadNum++;
if (stateRef.current.loadNum === list.length) {
onSize();
}
};
const [columns, setColumns] = useState([[], [], [], []]);
const onSize = () => {
let res = [[], [], [], []];
let columnHeights = [0, 0, 0, 0];
rendered.map((renderItem, index) => {
let minHeight = Infinity;
let minHeightIndex = 0;
for (let i = 0; i < columnNumber; ++i) {
if (minHeight > columnHeights[i]) {
minHeight = columnHeights[i];
minHeightIndex = i;
}
}
res[minHeightIndex].push(renderItem);
columnHeights[minHeightIndex] += stateRef.current.heights[minHeightIndex];
});
setColumns(res);
};
const waterfallDOM = useRef();
const size = useSize(waterfallDOM);
useEffect(() => {
onSize();
}, [size, columnNumber]);
const rendered = list.map((item, index) => (
<WaterfallItem onLoad={(size) => onload(index, size.height)} data={item} />
));
return (
<div ref={waterfallDOM} className="waterfallContainer">
{columns.map((column) => {
return (
<div
style={{
width: `calc(${100 / columnNumber}% - 16px)`,
}}
>
{column}
</div>
);
})}
</div>
);
};
export default WaterfallPosition;

View File

@ -3,6 +3,7 @@ import ReactDOM from "react-dom/client";
import HomeRoute from "./routes/HomeRoute"; import HomeRoute from "./routes/HomeRoute";
import AboutRoute from "./routes/AboutRoute"; import AboutRoute from "./routes/AboutRoute";
import AwardsRoute from "./routes/AwardsRoute"; import AwardsRoute from "./routes/AwardsRoute";
import ProjectsRoute from "./routes/ProjectsRoute";
import reportWebVitals from "./reportWebVitals"; import reportWebVitals from "./reportWebVitals";
import { createBrowserRouter, RouterProvider } from "react-router-dom"; import { createBrowserRouter, RouterProvider } from "react-router-dom";
import ErrorRoute from "./routes/ErrorRoute"; import ErrorRoute from "./routes/ErrorRoute";
@ -25,6 +26,11 @@ const router = createBrowserRouter([
path: "/awards", path: "/awards",
element: <AwardsRoute></AwardsRoute>, element: <AwardsRoute></AwardsRoute>,
errorElement: <ErrorRoute></ErrorRoute>, errorElement: <ErrorRoute></ErrorRoute>,
},
{
path: "/projects",
element: <ProjectsRoute></ProjectsRoute>,
errorElement: <ErrorRoute></ErrorRoute>,
} }
]); ]);

View File

@ -0,0 +1,12 @@
import AppOuter from "../components/AppOuter";
import Projects from "../components/Projects";
const ProjectsRoute = () => {
return (
<AppOuter>
<Projects />
</AppOuter>
);
};
export default ProjectsRoute;