Compare commits
15 Commits
feature/ad
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
57ab55bc45 | ||
|
691ae1e3f9 | ||
|
6437bc7371 | ||
|
251a9c7210 | ||
|
4695dea933 | ||
|
086b2087b1 | ||
|
84e7889653 | ||
|
a883ebe2ef | ||
|
43d66d50ae | ||
2300d2bbf3 | |||
118c39afb8 | |||
b08e0e9b4e | |||
|
a859b2824f | ||
|
a6b5fc79fa | ||
858b9e0f27 |
1622
package-lock.json
generated
@ -8,6 +8,7 @@
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"ahooks": "^3.7.8",
|
||||
"animate.css": "^4.1.1",
|
||||
"antd": "^5.9.2",
|
||||
"axios": "^1.3.2",
|
||||
"hamburger-react": "^2.5.0",
|
||||
"nodemon": "^2.0.20",
|
||||
|
108
src/assets/data/gallery.js
Normal file
@ -0,0 +1,108 @@
|
||||
import pic0 from "../pics/gallery/IMG_0796.jpg";
|
||||
import pic1 from "../pics/gallery/IMG_6390.jpg";
|
||||
import pic2 from "../pics/gallery/IMG_6392.jpg";
|
||||
import pic3 from "../pics/gallery/IMG_6393.jpg";
|
||||
import pic4 from "../pics/gallery/IMG_8547.jpg";
|
||||
import pic5 from "../pics/gallery/IMG_8548.jpg";
|
||||
import pic6 from "../pics/gallery/IMG_8549.jpg";
|
||||
import pic7 from "../pics/gallery/JSDC2011.jpg";
|
||||
import pic8 from "../pics/gallery/JSDC2012.jpg";
|
||||
import pic9 from "../pics/gallery/dsc_0001.jpg";
|
||||
import pic10 from "../pics/gallery/dsc_0003.jpg";
|
||||
import pic11 from "../pics/gallery/dsc_0235.jpg";
|
||||
import pic12 from "../pics/gallery/dsc_0238.jpg";
|
||||
import pic13 from "../pics/gallery/dsc_0243.jpg";
|
||||
import pic14 from "../pics/gallery/jsdc2015_001.jpg";
|
||||
import pic15 from "../pics/gallery/jsdc2015_002.jpg";
|
||||
import pic16 from "../pics/gallery/jsdc2015_003.jpg";
|
||||
|
||||
const gallery = {
|
||||
pic: [
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic0,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic1,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic2,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic3,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic4,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic5,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic6,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic7,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic8,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic9,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic10,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic11,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic12,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic13,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic14,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic15,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic16,
|
||||
}
|
||||
],
|
||||
};
|
||||
export default gallery;
|
80
src/assets/data/projects.js
Normal 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;
|
BIN
src/assets/pics/fancypants.jpg
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
src/assets/pics/fenrir.jpg
Normal file
After Width: | Height: | Size: 278 KiB |
BIN
src/assets/pics/gallery/IMG_0796.jpg
Normal file
After Width: | Height: | Size: 440 KiB |
BIN
src/assets/pics/gallery/IMG_6390.jpg
Normal file
After Width: | Height: | Size: 637 KiB |
BIN
src/assets/pics/gallery/IMG_6392.jpg
Normal file
After Width: | Height: | Size: 444 KiB |
BIN
src/assets/pics/gallery/IMG_6393.jpg
Normal file
After Width: | Height: | Size: 537 KiB |
BIN
src/assets/pics/gallery/IMG_8547.jpg
Normal file
After Width: | Height: | Size: 581 KiB |
BIN
src/assets/pics/gallery/IMG_8548.jpg
Normal file
After Width: | Height: | Size: 542 KiB |
BIN
src/assets/pics/gallery/IMG_8549.jpg
Normal file
After Width: | Height: | Size: 554 KiB |
BIN
src/assets/pics/gallery/JSDC2011.jpg
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/pics/gallery/JSDC2012.jpg
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/pics/gallery/dsc_0001.jpg
Normal file
After Width: | Height: | Size: 913 KiB |
BIN
src/assets/pics/gallery/dsc_0003.jpg
Normal file
After Width: | Height: | Size: 898 KiB |
BIN
src/assets/pics/gallery/dsc_0235.jpg
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
src/assets/pics/gallery/dsc_0238.jpg
Normal file
After Width: | Height: | Size: 1.4 MiB |
BIN
src/assets/pics/gallery/dsc_0243.jpg
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
src/assets/pics/gallery/jsdc2015_001.jpg
Normal file
After Width: | Height: | Size: 1.4 MiB |
BIN
src/assets/pics/gallery/jsdc2015_002.jpg
Normal file
After Width: | Height: | Size: 1022 KiB |
BIN
src/assets/pics/gallery/jsdc2015_003.jpg
Normal file
After Width: | Height: | Size: 1.4 MiB |
26
src/assets/pics/gallery/readimg.js
Normal file
@ -0,0 +1,26 @@
|
||||
const fs = require("fs");
|
||||
|
||||
let res = "";
|
||||
let json = `const gallery = {
|
||||
pic: [`;
|
||||
|
||||
let jsonEnd = `
|
||||
],
|
||||
};`;
|
||||
fs.readdir("./", (err, files) => {
|
||||
files.forEach((file, index) => {
|
||||
if (file === "readimg.js") {
|
||||
return;
|
||||
}
|
||||
console.log(file);
|
||||
res += `import pic${index} from "../pics/gallery/${file}";\n`;
|
||||
json += `{
|
||||
title: "",
|
||||
content: "",
|
||||
img: pic${index}
|
||||
},`;
|
||||
});
|
||||
|
||||
console.log(res);
|
||||
console.log(json + jsonEnd);
|
||||
});
|
BIN
src/assets/pics/goliath.jpg
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
src/assets/pics/icarus.jpg
Normal file
After Width: | Height: | Size: 135 KiB |
BIN
src/assets/pics/mach2.jpg
Normal file
After Width: | Height: | Size: 173 KiB |
BIN
src/assets/pics/matchlock.jpg
Normal file
After Width: | Height: | Size: 147 KiB |
BIN
src/assets/pics/modulus.jpg
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
src/assets/pics/mongol.jpg
Normal file
After Width: | Height: | Size: 220 KiB |
BIN
src/assets/pics/osiris.jpg
Normal file
After Width: | Height: | Size: 2.6 MiB |
BIN
src/assets/pics/roomba.jpg
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
src/assets/pics/roslund.jpg
Normal file
After Width: | Height: | Size: 113 KiB |
@ -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 {
|
||||
0% {
|
||||
opacity: 0;
|
||||
|
@ -1,19 +1,26 @@
|
||||
#container {
|
||||
.c {
|
||||
opacity: 100%;
|
||||
-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-color: black;
|
||||
background: linear-gradient(#3b3b3b, #1a1a1a);
|
||||
position: relative;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: #232323;
|
||||
background-color: #3d3d3d;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
height: calc(100vh - 101px);
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.error__photo { margin: 0px;
|
||||
|
40
src/assets/stylesheets/gallery.scss
Normal file
@ -0,0 +1,40 @@
|
||||
@font-face {
|
||||
font-family: itrFont;
|
||||
src: url(../font/LeagueSpartan-ExtraBold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: itrFontMedium;
|
||||
src: url(../font/LeagueSpartan-Medium.ttf);
|
||||
}
|
||||
|
||||
.gallery {
|
||||
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);
|
||||
}
|
||||
|
||||
.gallery_wrap {
|
||||
flex-wrap: wrap;
|
||||
padding: 24px;
|
||||
margin-left: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: start;
|
||||
}
|
||||
.gallery__title {
|
||||
margin: 20px 0 20px 20px;
|
||||
font-family: itrFontMedium;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
@ -192,6 +192,7 @@ li a:hover {
|
||||
.hamburger-react {
|
||||
color: #fff;
|
||||
display: block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.navbar__hamburger {
|
||||
display: flex;
|
||||
|
174
src/assets/stylesheets/project.scss
Normal file
@ -0,0 +1,174 @@
|
||||
@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;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
8
src/assets/stylesheets/waterfall.scss
Normal file
@ -0,0 +1,8 @@
|
||||
.waterfallContainer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
.waterfallItem {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
27
src/components/AppOuter.js
Normal file
@ -0,0 +1,27 @@
|
||||
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";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const AppOuter = ({ children }) => {
|
||||
const { isHamburger, setIsHamburger } = useContainer(GlobalStore);
|
||||
const location = useLocation();
|
||||
useEffect(() => {
|
||||
setIsHamburger(false);
|
||||
}, [location.pathname]);
|
||||
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;
|
@ -1,22 +1,62 @@
|
||||
import React, { Component } from "react";
|
||||
import backgroundVideo from "../assets/video.mp4";
|
||||
import "../assets/stylesheets/home.scss";
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import "../assets/stylesheets/gallery.scss";
|
||||
import { useContainer } from "unstated-next";
|
||||
import GlobalStore from "../store/global";
|
||||
import gallery from "../assets/data/gallery";
|
||||
import WaterfallPosition from "./hooks/waterfall";
|
||||
import { Image } from "antd";
|
||||
|
||||
export default class Gallery extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="home">
|
||||
<video autoPlay loop muted className="home__video">
|
||||
<source src={backgroundVideo} type="video/mp4" />
|
||||
</video>
|
||||
<div className="home__content">
|
||||
<label className="home__content__title">
|
||||
ILLINOIS TECH
|
||||
<br />
|
||||
ROBOTICS
|
||||
</label>
|
||||
const Render = ({ onLoad, data, sizeRef }) => {
|
||||
return (
|
||||
<div className="gallery__content">
|
||||
<Image
|
||||
onLoad={() => {
|
||||
setTimeout(() => {
|
||||
onLoad(sizeRef.current.size);
|
||||
}, 100);
|
||||
}}
|
||||
onError={() =>
|
||||
setTimeout(() => {
|
||||
onLoad(sizeRef.current.size);
|
||||
}, 100)
|
||||
}
|
||||
width={"100%"}
|
||||
src={data.img}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Gallery = () => {
|
||||
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 (
|
||||
<div className="gallery">
|
||||
<div className="gallery__content">
|
||||
<div className="gallery__content__main">
|
||||
<div>
|
||||
<h1 className="gallery__title">Gallery</h1>
|
||||
<WaterfallPosition
|
||||
columnNumber={count}
|
||||
list={gallery.pic}
|
||||
Render={Render}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Gallery;
|
||||
|
@ -1,22 +1,100 @@
|
||||
import React, { Component } from "react";
|
||||
import backgroundVideo from "../assets/video.mp4";
|
||||
import "../assets/stylesheets/home.scss";
|
||||
|
||||
export default class Projects extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="home">
|
||||
<video autoPlay loop muted className="home__video">
|
||||
<source src={backgroundVideo} type="video/mp4" />
|
||||
</video>
|
||||
<div className="home__content">
|
||||
<label className="home__content__title">
|
||||
ILLINOIS TECH
|
||||
<br />
|
||||
ROBOTICS
|
||||
</label>
|
||||
</div>
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import "../assets/stylesheets/project.scss";
|
||||
import { useContainer } from "unstated-next";
|
||||
import GlobalStore from "../store/global";
|
||||
import projects from "../assets/data/projects";
|
||||
import WaterfallPosition from "./hooks/waterfall";
|
||||
import { Image } from "antd";
|
||||
const Render = ({ onLoad, data, sizeRef }) => {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
};
|
||||
const Project = () => {
|
||||
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 (
|
||||
<div className="project">
|
||||
<div className="project__content">
|
||||
<div className="project__content__main">
|
||||
<div>
|
||||
<h1 className="projects__title">Active Projects</h1>
|
||||
<WaterfallPosition
|
||||
columnNumber={count}
|
||||
list={projects.active}
|
||||
Render={Render}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="projects__title">Retired/Inactive Projects</h1>
|
||||
<WaterfallPosition
|
||||
columnNumber={count}
|
||||
list={projects.inactive}
|
||||
Render={Render}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* <WaterfallPositionDemo /> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Project;
|
||||
|
98
src/components/hooks/waterfall.js
Normal file
@ -0,0 +1,98 @@
|
||||
import { useDebounce, useSize, useThrottleFn } from "ahooks";
|
||||
import React, { useRef, useEffect, useState } from "react";
|
||||
import "../../assets/stylesheets/waterfall.scss";
|
||||
|
||||
const WaterfallItem = ({ data, onLoad, Render }) => {
|
||||
const ref = useRef();
|
||||
const size = useSize(ref);
|
||||
const sizeRef = useRef({});
|
||||
useEffect(() => {
|
||||
sizeRef.current.size = size;
|
||||
}, [size]);
|
||||
return (
|
||||
<div className="waterfallItem" ref={ref}>
|
||||
<Render
|
||||
onLoad={() => {
|
||||
setTimeout(() => {
|
||||
onLoad(sizeRef.current.size);
|
||||
}, 500);
|
||||
}}
|
||||
sizeRef={sizeRef}
|
||||
data={data}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const useWaterfall = ({ list, columnNumber, Render }) => {
|
||||
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);
|
||||
const { run: onSizeThrottle } = useThrottleFn(onSize, { wait: 5e2 });
|
||||
useEffect(() => {
|
||||
onSizeThrottle();
|
||||
}, [size, columnNumber]);
|
||||
const rendered = list.map((item, index) => (
|
||||
<WaterfallItem
|
||||
onLoad={(size) => onload(index, size.height)}
|
||||
data={item}
|
||||
Render={Render}
|
||||
/>
|
||||
));
|
||||
return {
|
||||
waterfallDOM,
|
||||
columns,
|
||||
};
|
||||
};
|
||||
|
||||
const WaterfallPosition = ({ columnNumber, list, Render }) => {
|
||||
const { waterfallDOM, columns } = useWaterfall({
|
||||
columnNumber,
|
||||
list,
|
||||
Render,
|
||||
});
|
||||
return (
|
||||
<div ref={waterfallDOM} className="waterfallContainer">
|
||||
{columns.map((column) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: `calc(${100 / columnNumber}% - 16px)`,
|
||||
}}
|
||||
>
|
||||
{column}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default WaterfallPosition;
|
22
src/index.js
@ -3,10 +3,12 @@ import ReactDOM from "react-dom/client";
|
||||
import HomeRoute from "./routes/HomeRoute";
|
||||
import AboutRoute from "./routes/AboutRoute";
|
||||
import AwardsRoute from "./routes/AwardsRoute";
|
||||
import ProjectsRoute from "./routes/ProjectsRoute";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import ErrorRoute from "./routes/ErrorRoute";
|
||||
import GlobalStore from "./store/global";
|
||||
import GalleryRoute from "./routes/GalleryRoute";
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||
|
||||
@ -25,11 +27,23 @@ const router = createBrowserRouter([
|
||||
path: "/awards",
|
||||
element: <AwardsRoute></AwardsRoute>,
|
||||
errorElement: <ErrorRoute></ErrorRoute>,
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/projects",
|
||||
element: <ProjectsRoute></ProjectsRoute>,
|
||||
errorElement: <ErrorRoute></ErrorRoute>,
|
||||
},
|
||||
{
|
||||
path: "/gallery",
|
||||
element: <GalleryRoute></GalleryRoute>,
|
||||
errorElement: <ErrorRoute></ErrorRoute>,
|
||||
},
|
||||
]);
|
||||
|
||||
root.render(<GlobalStore.Provider>
|
||||
<RouterProvider router={router}></RouterProvider>
|
||||
</GlobalStore.Provider>);
|
||||
root.render(
|
||||
<GlobalStore.Provider>
|
||||
<RouterProvider router={router}></RouterProvider>
|
||||
</GlobalStore.Provider>
|
||||
);
|
||||
|
||||
reportWebVitals();
|
||||
|
@ -0,0 +1,12 @@
|
||||
import AppOuter from "../components/AppOuter";
|
||||
import Gallery from "../components/Gallery";
|
||||
|
||||
const GalleryRoute = () => {
|
||||
return (
|
||||
<AppOuter>
|
||||
<Gallery />
|
||||
</AppOuter>
|
||||
);
|
||||
};
|
||||
|
||||
export default GalleryRoute;
|
@ -0,0 +1,12 @@
|
||||
import AppOuter from "../components/AppOuter";
|
||||
import Projects from "../components/Projects";
|
||||
|
||||
const ProjectsRoute = () => {
|
||||
return (
|
||||
<AppOuter>
|
||||
<Projects />
|
||||
</AppOuter>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectsRoute;
|