formatting, readme, webp images, updated officers

- added prettier config
- added missing officers
- reordered officers based on official roster
- removed unused assets
- added project description
- fixed mismatching licenses
- optimized images to webp
    - reduced project size by 95%
This commit is contained in:
Raymond Wang 2022-10-22 12:27:16 -07:00
parent 1d9072030e
commit 3dc2eef6e1
54 changed files with 3882 additions and 939 deletions

4
.prettierrc Normal file
View file

@ -0,0 +1,4 @@
{
"tabWidth": 4,
"useTabs": false
}

View file

@ -1,2 +1,27 @@
# NewWebsite
The new IEEE website for the section at UCSD
# IEEE @ UCSD Website
## Deployment
Github Actions have been set to trigger on each push and pull request on the `main` branch. The website will be built as static pages to the `page` branch where it will be deployed onto [ieeeucsd.edu](https://ieeeucsd.edu).
## Contributing
Please create a new branch for development (i.e. `[NAME]-dev`). Pushing directly to main is not advised, as changes will go straight into production.
### Testing
To build the site, run `npm run build`.
To view the site on your local network, run `npm build/index.js`. View the site at [localhost:9000](http://localhost:9000).
### Images
Large images should be in WebP format. Consider resizing images based on their usage.
[Squoosh](https://squoosh.app/) is a great online tool for optimizing images developed by Google Chrome Labs.
### Formatting
Install [prettier](https://prettier.io/) and use it as the default Typescript and Javascript formatter. The `.prettierrc` configuration file controls the formatting rules.
For CSS, use `CSS Language Features` as the default formatter. For HTML, use `HTML Language Features` as the default formatter.

2547
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,10 @@
{
"name": "ieee-website",
"version": "1.0.0",
"description": "",
"description": "Website for IEEE of UC San Diego",
"main": "build/index.js",
"scripts": {
"build": "webpack & tsc & time /T",
"build": "webpack & tsc",
"watch": "npm-watch build"
},
"watch": {
@ -19,7 +19,7 @@
},
"keywords": [],
"author": "",
"license": "ISC",
"license": "MIT",
"dependencies": {
"@types/express": "^4.17.13",
"@types/node": "^16.11.7",
@ -35,14 +35,21 @@
"@babel/preset-env": "^7.15.8",
"@babel/preset-react": "^7.14.5",
"@types/react": "^16.14.20",
"@typescript-eslint/eslint-plugin": "^5.40.1",
"babel-loader": "^8.2.3",
"copy-webpack-plugin": "^6.4.1",
"css-loader": "^5.2.7",
"eslint": "^8.26.0",
"eslint-config-standard-with-typescript": "^23.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.3.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.31.10",
"html-webpack-plugin": "^4.5.2",
"license-webpack-plugin": "^2.3.21",
"style-loader": "^2.0.0",
"ts-loader": "^8.3.0",
"typescript": "^4.4.4",
"typescript": "^4.8.4",
"webpack": "^5.60.0",
"webpack-cli": "^4.9.1"
}

View file

@ -1,11 +1,13 @@
import {Schema, Document, LeanDocument} from "mongoose";
import { Schema, Document, LeanDocument } from "mongoose";
import * as mongoose from "mongoose";
import {promisify} from "util";
import {randomBytes, pbkdf2} from "crypto";
import { promisify } from "util";
import { randomBytes, pbkdf2 } from "crypto";
const pbkdf = promisify(pbkdf2);
const User = mongoose.model("User", new Schema({
const User = mongoose.model(
"User",
new Schema({
display: String,
email: {
public: Boolean,
@ -14,19 +16,20 @@ const User = mongoose.model("User", new Schema({
picture: String,
password: {
hash: Buffer,
salt: Buffer
salt: Buffer,
},
bio: {type: String, default: ""},
isOfficer: {type: Boolean, default: false},
title: {type: String, default: "Member"},
uuid: String
}));
bio: { type: String, default: "" },
isOfficer: { type: Boolean, default: false },
title: { type: String, default: "Member" },
uuid: String,
})
);
export interface DBUser extends Document {
display: string;
email: string;
picture: string;
password: HashSalt
password: HashSalt;
isOfficer: boolean;
title: string;
uuid: string;
@ -37,7 +40,6 @@ interface HashSalt {
}
export default class UserDatabase {
// How many iterations pbkdf2 will iterate the password hashing algorithm
private static PW_ITERATIONS = 100000;
// The length of the salt that should be used with every password hash
@ -61,7 +63,7 @@ export default class UserDatabase {
* @param newName the user's new name
*/
public async setName(uuid: string, newName: string) {
await User.findOneAndUpdate({uuid: uuid}, {name: newName}).exec();
await User.findOneAndUpdate({ uuid: uuid }, { name: newName }).exec();
}
/**
* Gets the display name of a user with a given UUID
@ -69,7 +71,8 @@ export default class UserDatabase {
* @returns the user's display name
*/
public async getName(uuid: string): Promise<string> {
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).display;
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
.display;
}
/**
@ -78,7 +81,7 @@ export default class UserDatabase {
* @param newEmail the user's new display email
*/
public async setEmail(uuid: string, newEmail: string) {
await User.findOneAndUpdate({uuid: uuid}, {email: newEmail}).exec();
await User.findOneAndUpdate({ uuid: uuid }, { email: newEmail }).exec();
}
/**
* Gets the email of a user with a given UUID
@ -86,7 +89,8 @@ export default class UserDatabase {
* @returns the user's email
*/
public async getEmail(uuid: string): Promise<string> {
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).email;
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
.email;
}
/**
@ -96,7 +100,10 @@ export default class UserDatabase {
*/
public async setPassword(uuid: string, newPassword: string) {
let hashsalt = await UserDatabase.hash(newPassword);
await User.findOneAndUpdate({uuid: uuid}, {password: hashsalt}).exec();
await User.findOneAndUpdate(
{ uuid: uuid },
{ password: hashsalt }
).exec();
}
/**
* Gets the password of a user with a given UUID
@ -104,7 +111,8 @@ export default class UserDatabase {
* @returns the user's password
*/
public async getPasswordHash(uuid: string): Promise<Buffer> {
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).password.hash;
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
.password.hash;
}
/**
@ -113,7 +121,10 @@ export default class UserDatabase {
* @param newTitle the user's new officer title/position
*/
public async setRank(uuid: string, newTitle: string, isOfficer: boolean) {
await User.findOneAndUpdate({uuid: uuid}, {title: newTitle, isOfficer: isOfficer}).exec();
await User.findOneAndUpdate(
{ uuid: uuid },
{ title: newTitle, isOfficer: isOfficer }
).exec();
}
/**
* Gets the title of a user with a given UUID
@ -121,7 +132,8 @@ export default class UserDatabase {
* @returns the user's title
*/
public async getRank(uuid: string): Promise<string> {
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).title;
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
.title;
}
/**
* Gets whether of a user with a given UUID is an officer
@ -129,7 +141,8 @@ export default class UserDatabase {
* @returns true if the user is an officer
*/
public async isOfficer(uuid: string): Promise<boolean> {
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).isOfficer;
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
.isOfficer;
}
/**
@ -138,7 +151,7 @@ export default class UserDatabase {
* @param newPic the link to the new URL of the profile picture
*/
public async setPicture(uuid: string, newPic: string) {
await User.findOneAndUpdate({uuid: uuid}, {picture: newPic}).exec();
await User.findOneAndUpdate({ uuid: uuid }, { picture: newPic }).exec();
}
/**
* Gets the profile picture of a user with a given UUID
@ -146,11 +159,12 @@ export default class UserDatabase {
* @returns the user's profile picture
*/
public async getPicture(uuid: string): Promise<string> {
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).picture;
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
.picture;
}
public async getUser(uuid: string): Promise<DBUser> {
return User.findOne({uuid: uuid}).exec() as Promise<DBUser>;
return User.findOne({ uuid: uuid }).exec() as Promise<DBUser>;
}
// User creation and deletion functions
@ -159,7 +173,7 @@ export default class UserDatabase {
* @param uuid the UUID of the user
*/
public async deleteUser(uuid: string) {
await User.findOneAndDelete({uuid: uuid}).exec();
await User.findOneAndDelete({ uuid: uuid }).exec();
}
/**
@ -169,17 +183,24 @@ export default class UserDatabase {
* @param picture the user's picture
* @param password the user's plaintext password
*/
public async makeNewUser(display: string, email: string, picture: string, password: string, title?: string, isOfficer?: boolean): Promise<void> {
public async makeNewUser(
display: string,
email: string,
picture: string,
password: string,
title?: string,
isOfficer?: boolean
): Promise<void> {
let encrypted = await UserDatabase.hash(password);
await (new User({
await new User({
display: display,
email: email,
picture: picture,
password: encrypted,
uuid: UserDatabase.genUUID(),
isOfficer: !!isOfficer,
title: title ? title : "Member"
})).save();
title: title ? title : "Member",
}).save();
}
// Utility functions
@ -192,8 +213,14 @@ export default class UserDatabase {
let salt = randomBytes(UserDatabase.SALT_LENGTH);
let pass = Buffer.from(String.prototype.normalize(password));
return {
hash: await pbkdf(pass, salt, UserDatabase.PW_ITERATIONS, 512, "sha512"),
salt: salt
hash: await pbkdf(
pass,
salt,
UserDatabase.PW_ITERATIONS,
512,
"sha512"
),
salt: salt,
};
}
@ -203,6 +230,7 @@ export default class UserDatabase {
*/
public static genUUID(): string {
return Array.from(randomBytes(UserDatabase.UUID_LENGTH))
.map(val=>(val.toString(16).padStart(2,"0"))).join("");
.map((val) => val.toString(16).padStart(2, "0"))
.join("");
}
}

View file

@ -1,5 +1,5 @@
import express from "express";
import {Request, Response} from "express";
import { Request, Response } from "express";
import * as path from "path";
import * as fs from "fs";
import UserDatabase from "./Database";
@ -14,77 +14,80 @@ interface Website {
themecolor: string;
}
const app = express();
const template = fs.readFileSync(path.join(__dirname, "public/template.html")).toString();
const websites = [{
const APP = express();
const TEMPLATE = fs
.readFileSync(path.join(__dirname, "public/template.html"))
.toString();
const WEBSITES = [
{
sitename: "index",
title: "IEEE at UCSD",
description: "",
jsfile: "js/index.js",
cssfile: "css/styles.css",
themecolor: ""
},
{
themecolor: "",
},
{
sitename: "events",
title: "IEEE at UCSD",
description: "",
jsfile: "js/events.js",
cssfile: "css/styles.css",
themecolor: ""
},
{
themecolor: "",
},
{
sitename: "projects",
title: "IEEE at UCSD",
description: "",
jsfile: "js/projects.js",
cssfile: "css/styles.css",
themecolor: ""
},
{
themecolor: "",
},
{
sitename: "committees",
title: "IEEE at UCSD",
description: "",
jsfile: "js/committees.js",
cssfile: "css/styles.css",
themecolor: ""
},
{
themecolor: "",
},
{
sitename: "contact",
title: "IEEE at UCSD",
description: "",
jsfile: "js/index.js",
cssfile: "css/styles.css",
themecolor: ""
}
themecolor: "",
},
] as Website[];
const PORT = 9000;
// Make the public directory traversible to people online
app.use(express.static(path.join(__dirname, "public")));
APP.use(express.static(path.join(__dirname, "public")));
// Put the cookies as a variable in the request
app.use((req: Request, res: Response, next: any)=>{
APP.use((req: Request, res: Response, next: any) => {
req.cookies = req.headers.cookie;
next();
});
// Receive json post requests and urlencoded requests
app.use(express.json());
app.use(express.urlencoded({extended: true}));
APP.use(express.json());
APP.use(express.urlencoded({ extended: true }));
// Send main page
app.get("/", (req: Request, res: Response) => {
APP.get("/", (req: Request, res: Response) => {
respond(res, "index");
});
app.get("/events", (req: Request, res: Response) => {
APP.get("/events", (req: Request, res: Response) => {
respond(res, "events");
});
app.get("/projects", (req: Request, res: Response) => {
APP.get("/projects", (req: Request, res: Response) => {
respond(res, "projects");
});
app.get("/committees", (req: Request, res: Response) => {
APP.get("/committees", (req: Request, res: Response) => {
respond(res, "committees");
});
app.get("/contact", (req: Request, res: Response) => {
APP.get("/contact", (req: Request, res: Response) => {
respond(res, "contact");
});
@ -93,14 +96,14 @@ app.get("/contact", (req: Request, res: Response) => {
*/
function respond(res: any, filename: string) {
res.set({
"Content-Type": "text/html"
"Content-Type": "text/html",
});
res.send(generatePage(filename));
}
function generatePage(name: string): string {
let site = websites.find(e=>e.sitename===name);
let html = template;
let site = WEBSITES.find((e) => e.sitename === name);
let html = TEMPLATE;
for (let key of Object.keys(site)) {
html = html.replace(new RegExp("\\$" + key.toUpperCase()), site[key]);
}
@ -108,14 +111,19 @@ function generatePage(name: string): string {
}
function generateFilePages() {
for (let site of websites) {
for (let site of WEBSITES) {
let html = generatePage(site.sitename);
fs.writeFileSync(require("path").join(__dirname, "public/", `${site.sitename}.html`), html);
fs.writeFileSync(
require("path").join(__dirname, "public/", `${site.sitename}.html`),
html
);
}
}
if (process.argv[2] === "generate") {
generateFilePages();
} else {
app.listen(PORT, "127.0.0.1");
APP.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});
}

View file

@ -1,171 +1,237 @@
// The links that are on the top nav bar that link to a lowercase version of their page
export const ACTIVE_PAGES = [{
export const ACTIVE_PAGES = [
{
name: "Home",
url: "/"
}, {
url: "/",
},
{
name: "Events",
url: "/events"
}, {
url: "/events",
},
{
name: "Projects",
url: "/projects"
}, {
url: "/projects",
},
{
name: "Committees",
url: "/committees"
}, {
url: "/committees",
},
{
name: "Contact Us",
url: "/contact"
}];
url: "/contact",
},
];
// Urls of team photos that will go in the "About" slideshow
export const TEAM_PHOTOS: string[] = [];
export const PROJECT_SPACE: string[] = [];
export const EVENTS: any[] = [];
export const SOCIALS = [{
export const SOCIALS = [
{
icon: "img/disc.svg",
url: "https://discord.gg/XxfjqZSjca",
message: "Join our server"
}, {
message: "Join our server",
},
{
icon: "img/fab.svg",
url: "https://www.facebook.com/ieeeucsd",
message: "ieeeucsd"
}, {
message: "ieeeucsd",
},
{
icon: "img/inst.svg",
url: "https://www.instagram.com/ieee.ucsd",
message: "@ieeeucsd"
}];
export const EMAIL = [{
message: "@ieeeucsd",
},
];
export const EMAIL = [
{
icon: "img/email.svg",
url: "mailto:ieee@eng.ucsd.edu",
message: "ieee@eng.ucsd.edu"
}];
export const EMAIL_WHITE = [{
message: "ieee@eng.ucsd.edu",
},
];
export const EMAIL_WHITE = [
{
icon: "img/email_white.svg",
url: "mailto:ieee@eng.ucsd.edu",
message: "ieee@eng.ucsd.edu"
}]
message: "ieee@eng.ucsd.edu",
},
];
export const SOCIALS_WHITE = [{
export const SOCIALS_WHITE = [
{
icon: "img/disc_white.svg",
url: "https://discord.gg/XxfjqZSjca",
message: "Join our server"
}, {
message: "Join our server",
},
{
icon: "img/fab_white.svg",
url: "https://www.facebook.com/ieeeucsd",
message: "ieeeucsd"
}, {
message: "ieeeucsd",
},
{
icon: "img/inst_white.svg",
url: "https://www.instagram.com/ieee.ucsd",
message: "@ieeeucsd"
}];
export const OFFICERS = [{
message: "@ieeeucsd",
},
];
export const OFFICERS = [
{
name: "Darin Tsui",
position: "Chair",
photo: "img/officers/darin.jpg",
email: "email@ucsd.edu"
}, {
email: "email@ucsd.edu",
},
{
name: "Brigette Hacia",
position: "Vice Chair Internal",
photo: "img/officers/brigette.jpg",
email: "email@ucsd.edu"
}, {
email: "email@ucsd.edu",
},
{
name: "Tasnia Jamal",
position: "Vice Chair Events",
photo: "img/officers/tasnia.jpg",
email: "email@ucsd.edu"
}, {
email: "email@ucsd.edu",
},
{
name: "Kevin Chang",
position: "Vice Chair Projects",
photo: "img/officers/kevin.jpg",
email: "email@ucsd.edu"
}, {
name: "Niklas Chang",
position: "Events Coordinator",
photo: "img/officers/niklas.jpg",
email: "email@ucsd.edu"
}, {
name: "Tien Vu",
position: "Vice Chair External",
photo: "img/officers/tien.jpg",
email: "email@ucsd.edu"
}, {
email: "email@ucsd.edu",
},
{
name: "Arjun Sampath",
position: "Vice Chair Finance",
photo: "img/officers/arjun.jpg",
email: "email@ucsd.edu"
}, {
email: "email@ucsd.edu",
},
{
name: "Niklas Chang",
position: "Events Coordinator",
photo: "img/officers/niklas.jpg",
email: "email@ucsd.edu",
},
{
name: "Tien Vu",
position: "Vice Chair External",
photo: "img/officers/tien.jpg",
email: "email@ucsd.edu",
},
{
name: "Derek Nguyen",
position: "Project Space Chair",
photo: "img/officers/derek.jpg",
email: "email@ucsd.edu"
}, {
name: "Mohak Vaswani",
position: "Technical Chair",
photo: "img/officers/mohak.jpg",
email: "email@ucsd.edu"
}, {
name: "Parisa Shahabi",
position: "Social Chair",
photo: "img/officers/parisa.jpg",
email: "email@ucsd.edu"
}, {
name: "Vuong Bui",
position: "Professional Chair",
photo: "img/officers/vuong.jpg",
email: "email@ucsd.edu"
}, {
name: "Jason Liang",
position: "Professional Chair",
photo: "img/officers/jason.jpg",
email: "email@ucsd.edu"
}, {
name: "Daniel Chen",
position: "Outreach Chair",
photo: "img/officers/daniel.jpg",
email: "email@ucsd.edu"
}, {
name: "Dennis Liang",
position: "Outreach Chair",
photo: "img/officers/dennis.jpg",
email: "email@ucsd.edu"
}, {
name: "Yash Puneet",
position: "Robocup Chair",
photo: "img/officers/yash.jpg",
email: "email@ucsd.edu"
}, {
email: "email@ucsd.edu",
},
{
name: "Rafaella Gomes",
position: "Robocup Chair",
photo: "img/officers/rafaella.jpg",
email: "email@ucsd.edu"
}, {
name: "Josh Lapidario",
position: "Quarterly Projects Chair",
photo: "img/officers/josh.jpg",
email: "email@ucsd.edu"
}, {
name: "Jiliana Tiu",
position: "Webmaster",
photo: "img/officers/jiliana.jpg",
email: "email@ucsd.edu"
}, {
name: "Stephanie Xu",
position: "PR Chair - Graphics",
photo: "img/officers/stephanie.jpg",
email: "email@ucsd.edu"
}, {
name: "Sankalp Kaushik",
position: "PR Chair - Media",
photo: "img/officers/sankalp.jpg",
email: "email@ucsd.edu"
}, {
email: "email@ucsd.edu",
},
{
name: "Yash Puneet",
position: "Robocup Chair",
photo: "img/officers/yash.jpg",
email: "email@ucsd.edu",
},
{
name: "Matthew Mikhailov",
position: "Supercomputing Chair",
photo: "img/officers/temp.png",
email: "email@ucsd.edu"
}, {
email: "email@ucsd.edu",
},
{
name: "Josh Lapidario",
position: "Quarterly Projects Chair",
photo: "img/officers/josh.jpg",
email: "email@ucsd.edu",
},
{
name: "Sanh Nguyen",
position: "Quarterly Projects Chair",
photo: "img/officers/temp.png",
email: "email@ucsd.edu",
},
{
name: "Vuong Bui",
position: "Professional Chair",
photo: "img/officers/vuong.jpg",
email: "email@ucsd.edu",
},
{
name: "Jason Liang",
position: "Professional Chair",
photo: "img/officers/jason.jpg",
email: "email@ucsd.edu",
},
{
name: "Mohak Vaswani",
position: "Technical Chair",
photo: "img/officers/mohak.jpg",
email: "email@ucsd.edu",
},
{
name: "Yusuf Morsi",
position: "Technical Chair",
photo: "img/officers/temp.png",
email: "email@ucsd.edu",
},
{
name: "Shaun Garcia",
position: "Technical Chair",
photo: "img/officers/temp.png",
email: "email@ucsd.edu",
},
{
name: "Dennis Liang",
position: "Outreach Chair",
photo: "img/officers/dennis.jpg",
email: "email@ucsd.edu",
},
{
name: "Daniel Chen",
position: "Outreach Chair",
photo: "img/officers/daniel.jpg",
email: "email@ucsd.edu",
},
{
name: "Parisa Shahabi",
position: "Social Chair",
photo: "img/officers/parisa.jpg",
email: "email@ucsd.edu",
},
{
name: "Matthew Yik",
position: "Social Chair",
photo: "img/officers/temp.png",
email: "email@ucsd.edu",
},
{
name: "Jiliana Tiu",
position: "Webmaster",
photo: "img/officers/jiliana.jpg",
email: "email@ucsd.edu",
},
{
name: "Raymond Wang",
position: "Webmaster",
photo: "img/officers/temp.png",
email: "raymond@ucsd.edu"
}];
email: "raymond@ucsd.edu",
},
{
name: "Sankalp Kaushik",
position: "PR Chair - Media",
photo: "img/officers/sankalp.jpg",
email: "email@ucsd.edu",
},
{
name: "Stephanie Xu",
position: "PR Chair - Graphics",
photo: "img/officers/stephanie.jpg",
email: "email@ucsd.edu",
},
];

View file

@ -1,7 +1,7 @@
import * as ReactDom from "react-dom";
import * as React from "react";
import TopBar from "./components/TopBar";
import {ACTIVE_PAGES, SOCIALS, EMAIL, OFFICERS} from "./Config";
import { ACTIVE_PAGES, SOCIALS, EMAIL, OFFICERS } from "./Config";
import Splash from "./components/Splash";
import DefaultSection from "./components/DefaultSection";
import InvolveBox from "./components/InvolveBox";
@ -18,38 +18,73 @@ class Main extends React.Component<MainProps, MainState> {
this.state = {};
}
public render() {
return <>
return (
<>
<TopBar links={ACTIVE_PAGES}></TopBar>
<Splash cta="The backbone of IEEE. Come help make a difference!" delay={2000} backgrounds={["img/backgrounds/committee.png"]}></Splash>
<DefaultSection title="Join us!" paragraphs={[
"Interested in gaining experience of event planning and development, meeting new friends, and learning more about IEEE? Join one of our committees as an IEEEntern!"
]}>
</DefaultSection>
<Splash
cta="The backbone of IEEE. Come help make a difference!"
delay={2000}
backgrounds={["img/backgrounds/committee.webp"]}
></Splash>
<DefaultSection
title="Join us!"
paragraphs={[
"Interested in gaining experience of event planning and development, meeting new friends, and learning more about IEEE? Join one of our committees as an IEEEntern!",
]}
></DefaultSection>
<DefaultSection className={"our-comms"} title="Our Committees">
<div className="cards">
<InvolveBox boxTitle="" image="img/committees/technical.jpg" description="Technical Committee"></InvolveBox>
<InvolveBox boxTitle="" image="img/committees/social.jpg" description="Social Committee"></InvolveBox>
<InvolveBox boxTitle="" image="img/committees/professional.jpg" description="Professional Committee"></InvolveBox>
<InvolveBox boxTitle="" image="img/committees/pr.jpg" description="PR Committee"></InvolveBox>
<InvolveBox boxTitle="" image="img/committees/outreach.jpg" description="Outreach Committee"></InvolveBox>
<InvolveBox
boxTitle=""
image="img/committees/technical.webp"
description="Technical Committee"
></InvolveBox>
<InvolveBox
boxTitle=""
image="img/committees/social.webp"
description="Social Committee"
></InvolveBox>
<InvolveBox
boxTitle=""
image="img/committees/professional.webp"
description="Professional Committee"
></InvolveBox>
<InvolveBox
boxTitle=""
image="img/committees/pr.webp"
description="PR Committee"
></InvolveBox>
<InvolveBox
boxTitle=""
image="img/committees/outreach.webp"
description="Outreach Committee"
></InvolveBox>
</div>
</DefaultSection>
<div id="contact-us">
<DefaultSection title="Interested? Join our socials!">
<div className="join-scls">{
[...EMAIL, ...SOCIALS].map(n => (
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
))
}</div>
<div className="join-scls">
{[...EMAIL, ...SOCIALS].map((n) => (
<SocialCard
url={n.url}
image={n.icon}
message={n.message}
></SocialCard>
))}
</div>
</DefaultSection>
<DefaultSection className="contact" title="Or... Contact one of our staff!">
<DefaultSection
className="contact"
title="Or... Contact one of our staff!"
>
<Carousel items={OFFICERS} itemsPerPage={6}></Carousel>
</DefaultSection>
</div>
<Footer></Footer>
</>;
</>
);
}
}

View file

@ -1,5 +1,5 @@
import * as React from "react";
import {Component} from "react";
import { Component } from "react";
import { CarouselItemProps } from "./CarouselItem";
import CarouselPage from "./CarouselPage";
@ -15,41 +15,65 @@ export default class Carousel extends Component<CarouselProps, CarouselState> {
constructor(props: CarouselProps) {
super(props);
this.state = {
page: 0
page: 0,
};
}
private prevPage() {
this.setState({page: this.state.page - 1 < 0 ? 0 : this.state.page - 1});
this.setState({
page: this.state.page - 1 < 0 ? 0 : this.state.page - 1,
});
}
private nextPage() {
this.setState({ page: this.state.page + 1 > Math.ceil(this.props.items.length / this.props.itemsPerPage) - 1 ?
Math.ceil(this.props.items.length / this.props.itemsPerPage) - 1 :
this.state.page + 1
this.setState({
page:
this.state.page + 1 >
Math.ceil(this.props.items.length / this.props.itemsPerPage) - 1
? Math.ceil(
this.props.items.length / this.props.itemsPerPage
) - 1
: this.state.page + 1,
});
}
public render() {
let arr = this.chunkArray(this.props.items);
return <div className="carousel">
<img className="carousel-left" src="img/arrow.svg" style={
this.state.page === 0 ? {visibility: "hidden"} : {}
} onClick={this.prevPage.bind(this)}></img>
<div className="carousel-items">{
arr.map((items, i)=>(
<CarouselPage items={items} visible={i===this.state.page}></CarouselPage>
))
}</div>
<img className="carousel-right" src="img/arrow.svg" style={
this.state.page === arr.length - 1 ? {visibility: "hidden"} : {}
} onClick={this.nextPage.bind(this)}></img>
</div>;
return (
<div className="carousel">
<img
className="carousel-left"
src="img/arrow.svg"
style={
this.state.page === 0 ? { visibility: "hidden" } : {}
}
onClick={this.prevPage.bind(this)}
></img>
<div className="carousel-items">
{arr.map((items, i) => (
<CarouselPage
items={items}
visible={i === this.state.page}
></CarouselPage>
))}
</div>
<img
className="carousel-right"
src="img/arrow.svg"
style={
this.state.page === arr.length - 1
? { visibility: "hidden" }
: {}
}
onClick={this.nextPage.bind(this)}
></img>
</div>
);
}
private chunkArray(array: CarouselItemProps[]):CarouselItemProps[][] {
private chunkArray(array: CarouselItemProps[]): CarouselItemProps[][] {
let returnArr = [] as CarouselItemProps[][];
for(let i = 0; i < array.length; i+=this.props.itemsPerPage) {
for (let i = 0; i < array.length; i += this.props.itemsPerPage) {
returnArr.push(array.slice(i, i + this.props.itemsPerPage));
}
return returnArr;

View file

@ -1,5 +1,5 @@
import * as React from "react";
import {Component} from "react";
import { Component } from "react";
export interface CarouselItemProps {
name: string;
@ -9,17 +9,22 @@ export interface CarouselItemProps {
}
interface CarouselItemState {}
export default class CarouselItem extends Component<CarouselItemProps, CarouselItemState> {
export default class CarouselItem extends Component<
CarouselItemProps,
CarouselItemState
> {
constructor(props: CarouselItemProps) {
super(props);
this.state = {};
}
public render() {
return <div className="carousel-item">
return (
<div className="carousel-item">
<img src={this.props.photo}></img>
<div className="carousel-name">{this.props.name}</div>
<div className="carousel-pos">{this.props.position}</div>
</div>;
</div>
);
}
}

View file

@ -1,5 +1,5 @@
import * as React from "react";
import {Component} from "react";
import { Component } from "react";
import CarouselItem, { CarouselItemProps } from "./CarouselItem";
interface CarouselPageProps {
@ -8,17 +8,25 @@ interface CarouselPageProps {
}
interface CarouselPageState {}
export default class CarouselPage extends Component<CarouselPageProps, CarouselPageState> {
export default class CarouselPage extends Component<
CarouselPageProps,
CarouselPageState
> {
constructor(props: CarouselPageProps) {
super(props);
this.state = {};
}
public render() {
return <div className="carousel-page" style={this.props.visible ? {} : {display: "none"}}>{
this.props.items.map(n=>(
return (
<div
className="carousel-page"
style={this.props.visible ? {} : { display: "none" }}
>
{this.props.items.map((n) => (
<CarouselItem {...n}></CarouselItem>
))
}</div>;
))}
</div>
);
}
}

View file

@ -1,5 +1,5 @@
import * as React from "react";
import {Component} from "react";
import { Component } from "react";
interface DefaultSectionProps {
title: string;
@ -8,19 +8,30 @@ interface DefaultSectionProps {
}
interface DefaultSectionState {}
export default class DefaultSection extends Component<DefaultSectionProps, DefaultSectionState> {
export default class DefaultSection extends Component<
DefaultSectionProps,
DefaultSectionState
> {
constructor(props: DefaultSectionProps) {
super(props);
this.state = {};
}
public render() {
return <div className={`default-section ${this.props.className ? this.props.className : ""}`}>
return (
<div
className={`default-section ${
this.props.className ? this.props.className : ""
}`}
>
<div className="section-title">{this.props.title}</div>
{(this.props.paragraphs ? this.props.paragraphs : []).map(n=>(
{(this.props.paragraphs ? this.props.paragraphs : []).map(
(n) => (
<p>{n}</p>
))}
)
)}
{this.props.children}
</div>;
</div>
);
}
}

View file

@ -1,7 +1,7 @@
import * as React from "react";
import {Component} from "react";
import { Component } from "react";
import SocialCard from "./SocialCard";
import {EMAIL_WHITE, SOCIALS_WHITE} from "../Config";
import { EMAIL_WHITE, SOCIALS_WHITE } from "../Config";
interface FooterProps {}
interface FooterState {}
@ -13,13 +13,19 @@ export default class Footer extends Component<FooterProps, FooterState> {
}
public render() {
return <div className="footer">
return (
<div className="footer">
<img src="img/logo_white.svg"></img>
<div className="footer-scls">{
[...EMAIL_WHITE, ...SOCIALS_WHITE].map(n => (
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
))
}</div>
</div>;
<div className="footer-scls">
{[...EMAIL_WHITE, ...SOCIALS_WHITE].map((n) => (
<SocialCard
url={n.url}
image={n.icon}
message={n.message}
></SocialCard>
))}
</div>
</div>
);
}
}

View file

@ -1,5 +1,5 @@
import * as React from "react";
import {Component} from "react";
import { Component } from "react";
interface InvolveBoxProps {
boxTitle: string;
@ -8,17 +8,29 @@ interface InvolveBoxProps {
}
interface InvolveBoxState {}
export default class InvolveBox extends Component<InvolveBoxProps, InvolveBoxState> {
export default class InvolveBox extends Component<
InvolveBoxProps,
InvolveBoxState
> {
constructor(props: InvolveBoxProps) {
super(props);
this.state = {};
}
public render() {
return <div className="involve-card">
<a className="involve-title" href={"/"+this.props.boxTitle.toLowerCase()}>{this.props.boxTitle}</a>
return (
<div className="involve-card">
<a
className="involve-title"
href={"/" + this.props.boxTitle.toLowerCase()}
>
{this.props.boxTitle}
</a>
<img src={this.props.image}></img>
<div className="involve-description">{this.props.description}</div>
</div>;
<div className="involve-description">
{this.props.description}
</div>
</div>
);
}
}

View file

@ -1,5 +1,5 @@
import * as React from "react";
import {Component} from "react";
import { Component } from "react";
interface SocialCardProps {
url: string;
@ -8,16 +8,21 @@ interface SocialCardProps {
}
interface SocialCardState {}
export default class SocialCard extends Component<SocialCardProps, SocialCardState> {
export default class SocialCard extends Component<
SocialCardProps,
SocialCardState
> {
constructor(props: SocialCardProps) {
super(props);
this.state = {};
}
public render() {
return <a href={this.props.url} className="social-card">
return (
<a href={this.props.url} className="social-card">
<img src={this.props.image}></img>
<div className="social-message">{this.props.message}</div>
</a>;
</a>
);
}
}

View file

@ -1,6 +1,6 @@
import * as React from "react";
import {Component} from "react";
import {SOCIALS_WHITE} from "../Config";
import { Component } from "react";
import { SOCIALS_WHITE } from "../Config";
interface SplashProps {
cta: string;
@ -16,31 +16,41 @@ export default class Splash extends Component<SplashProps, SplashState> {
constructor(props: SplashProps) {
super(props);
this.state = {
progress: 0
progress: 0,
};
this.interval = setInterval(this.changeImage.bind(this), this.props.delay) as any as number;
this.interval = setInterval(
this.changeImage.bind(this),
this.props.delay
) as any as number;
}
private changeImage(): void {
if (this.state.progress < this.props.backgrounds.length - 1) {
this.setState({progress: this.state.progress + 1});
this.setState({ progress: this.state.progress + 1 });
} else {
this.setState({progress: 0});
this.setState({ progress: 0 });
}
}
public render() {
return <div className="splash" style={{
backgroundImage: `url("${this.props.backgrounds[this.state.progress]}")`
}}>
return (
<div
className="splash"
style={{
backgroundImage: `url("${
this.props.backgrounds[this.state.progress]
}")`,
}}
>
<div className="call-to-action">{this.props.cta}</div>
<div className="splash-socials">{
SOCIALS_WHITE.map(n=>(
<div className="splash-socials">
{SOCIALS_WHITE.map((n) => (
<a href={n.url} key={n.icon}>
<img src={n.icon}></img>
</a>
))
}</div>
</div>;
))}
</div>
</div>
);
}
}

View file

@ -1,5 +1,5 @@
import * as React from "react";
import {Component} from "react";
import { Component } from "react";
interface TopBarProps {
links: {
@ -18,42 +18,65 @@ export default class TopBar extends Component<TopBarProps, TopBarState> {
super(props);
this.state = {
showBurger: this.shouldShowBurger(),
menuVisible: false
menuVisible: false,
};
window.addEventListener("resize", this.checkResize.bind(this));
}
private toggleMenu() {
this.setState({menuVisible: !this.state.menuVisible});
this.setState({ menuVisible: !this.state.menuVisible });
}
private checkResize() {
this.setState({showBurger: this.shouldShowBurger()});
this.setState({ showBurger: this.shouldShowBurger() });
}
private shouldShowBurger(): boolean {
return window.innerWidth < TopBar.HAMBURGER_POINT;
}
public render() {
return <div className={`topbar${
return (
<div
className={`topbar${
this.state.showBurger ? " burger-bar" : ""
}`}>
}`}
>
<div className="img-cont">
<a href="/"><img src="img/logo.svg"></img></a>
<div className="burger" style={{
display: this.state.showBurger ? "initial" : "none"
}} onClick={this.toggleMenu.bind(this)} role="menubar"></div>
<a href="/">
<img src="img/logo.svg"></img>
</a>
<div
className="burger"
style={{
display: this.state.showBurger ? "initial" : "none",
}}
onClick={this.toggleMenu.bind(this)}
role="menubar"
>
</div>
</div>
<div className="links">
<div className={`link-items${
<div
className={`link-items${
this.state.showBurger ? " burger-time" : ""
}`} style={{display: this.state.showBurger ?
(this.state.menuVisible ? "flex" : "none") :
"initial"}}>{
this.props.links.map(l=>{
return <a className="navlink" href={l.url}>{l.name}</a>
})
}</div>
}`}
style={{
display: this.state.showBurger
? this.state.menuVisible
? "flex"
: "none"
: "initial",
}}
>
{this.props.links.map((l) => {
return (
<a className="navlink" href={l.url}>
{l.name}
</a>
);
})}
</div>
</div>;
</div>
</div>
);
}
}

View file

@ -33,6 +33,7 @@
url('../fonts/roboto-v29-latin-700.woff') format('woff');
/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* montserrat-regular - latin */
@font-face {
font-family: 'Montserrat';

View file

@ -1,29 +1,34 @@
/* Color vars should go here */
/* Global CSS Properties */
:root {
--main: #00629B;
--accent: #FFCD00;
--secondary: white;
--dark: #2A1A4E;
--main: #00629b;
--accent: #ffcd00;
--secondary: #ffffff;
--dark: #2a1a4e;
}
* {
scrollbar-width: auto;
scrollbar-color: var(--main) transparent;
}
*::-webkit-scrollbar {
width: 0.6em;
height: 0.6em;
}
*::-webkit-scrollbar-track {
background: var(--main);
}
*::-webkit-scrollbar-thumb {
background-color: var(--secondary);
}
html {
font-family: "Roboto", sans-serif;
font-weight: bold;
}
body {
margin: 0;
}
@ -41,6 +46,7 @@ a:hover {
display: flex;
flex-direction: column;
}
.topbar {
display: flex;
flex-direction: row;
@ -50,20 +56,24 @@ a:hover {
padding: 0.5em;
align-items: center;
}
.topbar.burger-bar {
flex-direction: column;
position: relative;
}
.topbar.burger-bar > .img-cont {
.topbar.burger-bar>.img-cont {
align-self: flex-start;
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
}
.img-cont img {
width: 22em;
}
.burger {
font-size: 2.8em;
font-weight: normal;
@ -71,26 +81,31 @@ a:hover {
cursor: pointer;
margin-right: 0.3em;
}
.link-items.burger-time {
flex-direction: column;
position: absolute;
background-color: var(--secondary);
width: 10em;
box-shadow: rgba(0,0,0,0.3) 4px 4px 3px 0px;
box-shadow: rgba(0, 0, 0, 0.3) 4px 4px 3px 0px;
right: 0;
margin-top: 0.36em;
}
.link-items.burger-time > a {
.link-items.burger-time>a {
margin: 0;
padding: 0.4em 0.75em;
}
.link-items.burger-time > a:hover {
background-color: rgba(0,0,0,0.1);
.link-items.burger-time>a:hover {
background-color: rgba(0, 0, 0, 0.1);
}
.navlink {
font-size: 1.1em;
margin: 0.75em;
}
.splash {
background-color: var(--main);
background-blend-mode: overlay;
@ -104,6 +119,7 @@ a:hover {
background-repeat: no-repeat;
background-size: cover;
}
.call-to-action {
font-size: 3.2em;
width: 11em;
@ -111,16 +127,20 @@ a:hover {
text-align: center;
font-family: "Montserrat";
}
.splash-socials {
margin-top: 2em;
}
.splash-socials > a {
.splash-socials>a {
margin-left: 1.5em;
margin-right: 1.5em;
}
.splash-socials img {
width: 4.7em;
}
.default-section {
display: flex;
align-items: center;
@ -131,28 +151,34 @@ a:hover {
padding-top: 2em;
padding-bottom: 2em;
}
.section-title {
font-size: 3em;
margin-top: 0.8em;
margin-bottom: 0.8em;
}
.default-section > p, .project-space > p {
.default-section>p,
.project-space>p {
font-size: 1.8em;
width: 22em;
color: var(--dark);
text-align: center;
}
.project-space > p {
.project-space>p {
color: var(--secondary);
}
.default-section > p:first-child {
.default-section>p:first-child {
margin-top: 0;
}
.project-space {
border-radius: 50% 50% 0 0 / 4rem;
background-color: var(--main);
background-blend-mode: overlay;
background-image: url("../img/backgrounds/ps.png");
background-image: url("../img/backgrounds/ps.webp");
height: 40em;
display: flex;
justify-content: center;
@ -161,32 +187,39 @@ a:hover {
background-repeat: no-repeat;
background-size: cover;
}
.project-space a {
color: var(--accent);
}
.ps-title {
font-size: 3em;
color: white;
margin-bottom: 1em;
}
.visit-us {
font-size: 2em;
margin-bottom: 2em;
}
.ex-link {
color: var(--accent);
font-size: 2em;
margin-bottom: 2em;
}
.involved {
border-radius: 50% 50% 0 0 / 4rem;
transform: translateY(-4rem);
}
.cards {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
.involve-card {
padding: 1.75em 2.5em;
border: var(--main) solid 0.37em;
@ -198,32 +231,41 @@ a:hover {
flex-direction: column;
margin: 1em;
}
.involve-title {
font-size: 3em;
color: var(--main);
margin-bottom: 0.5em;
}
.involve-card > img {
.involve-card>img {
width: 20em;
margin-bottom: 1em;
border-radius: 0.2em;
}
.links {
font-size: 1.5em;
}
.social-card {
display: flex;
align-items: center;
padding: 1em;
width: 25em;
}
.social-card > img {
.social-card>img {
width: 4.7em;
}
.social-message {
font-size: 2em;
padding: 0.5em;
}
.join-scls, .footer-scls {
.join-scls,
.footer-scls {
display: flex;
flex-direction: row;
max-width: 55em;
@ -231,6 +273,7 @@ a:hover {
flex-wrap: wrap;
margin-left: 5em;
}
.carousel-item {
display: flex;
flex-direction: column;
@ -240,45 +283,58 @@ a:hover {
border-radius: 1em;
margin: 1em;
}
.carousel-item > img {
.carousel-item>img {
width: 18.7em;
border-radius: 0.2em;
}
.carousel-name {
font-size: 2em;
}
.carousel-pos {
font-style: italic;
font-weight: normal;
font-size: 1.25em;
}
.carousel-email {
margin-top: 0.5em;
}
.carousel-page {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.carousel {
display: flex;
align-items: center;
justify-content: center;
}
.carousel-left {
margin-left: 2em;
transform: scaleX(-1);
}
.carousel-right, .carousel-left {
.carousel-right,
.carousel-left {
cursor: pointer;
width: 4em;
}
.carousel-right {
margin-right: 2em;
}
.contact {
border-radius: 0 0 50% 50% / 4rem;
transform: translateY(4rem);
}
.footer {
background-color: var(--main);
padding-top: 7em;
@ -288,18 +344,22 @@ a:hover {
padding-left: 2em;
padding-right: 2em;
}
.footer a {
color: white;
}
.footer-scls {
max-width: 30em;
font-size: 0.6em;
margin-bottom: 2em;
}
.footer-scls img {
width: 4.7em;
}
.footer > img {
.footer>img {
width: 30em;
}
@ -309,27 +369,33 @@ a:hover {
font-size: 0.85em;
}
}
@media screen and (max-width: 650px) {
html {
font-size: 0.8em;
}
.footer > img{
.footer>img {
width: 15em;
}
}
@media screen and (max-width: 540px) {
html {
font-size: 0.6em;
}
.footer>img {
display: none;
}
}
@media screen and (max-width: 420px) {
html {
font-size: 0.5em;
}
}
@media screen and (max-width: 320px) {
html {
font-size: 0.45em;
@ -337,7 +403,7 @@ a:hover {
}
#cal {
border:solid 1px #777;
border: solid 1px #777;
width: 800px;
height: 600px;
}

View file

@ -1,7 +1,7 @@
import * as ReactDom from "react-dom";
import * as React from "react";
import TopBar from "./components/TopBar";
import {ACTIVE_PAGES, SOCIALS, EMAIL, OFFICERS} from "./Config";
import { ACTIVE_PAGES, SOCIALS, EMAIL, OFFICERS } from "./Config";
import Splash from "./components/Splash";
import DefaultSection from "./components/DefaultSection";
import InvolveBox from "./components/InvolveBox";
@ -18,30 +18,51 @@ class Main extends React.Component<MainProps, MainState> {
this.state = {};
}
public render() {
return <>
return (
<>
<TopBar links={ACTIVE_PAGES}></TopBar>
<Splash cta="Come out to our events!" delay={2000} backgrounds={["img/backgrounds/fa21social.png"]}></Splash>
<Splash
cta="Come out to our events!"
delay={2000}
backgrounds={["img/backgrounds/fa21social.webp"]}
></Splash>
<DefaultSection title="Events">
<iframe src="https://calendar.google.com/calendar/embed?src=666sh64sku5n29qv2a2f4598jc%40group.calendar.google.com&ctz=America%2FLos_Angeles" frameBorder="0" scrolling="no"></iframe>
<iframe
src="https://calendar.google.com/calendar/embed?src=666sh64sku5n29qv2a2f4598jc%40group.calendar.google.com&ctz=America%2FLos_Angeles"
frameBorder="0"
scrolling="no"
></iframe>
</DefaultSection>
<DefaultSection title="Open Access Hours">
<iframe src="https://calendar.google.com/calendar/embed?src=c_gr3iim9ae4dv9784qkf8meb40c%40group.calendar.google.com&ctz=America%2FLos_Angeles" frameBorder="0" scrolling="no"></iframe>
<iframe
src="https://calendar.google.com/calendar/embed?src=c_gr3iim9ae4dv9784qkf8meb40c%40group.calendar.google.com&ctz=America%2FLos_Angeles"
frameBorder="0"
scrolling="no"
></iframe>
</DefaultSection>
<div id="contact-us">
<DefaultSection className="contact" title="Have questions? Contact us!">
<div className="join-scls">{
[...EMAIL, ...SOCIALS].map(n => (
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
))
}</div>
<DefaultSection
className="contact"
title="Have questions? Contact us!"
>
<div className="join-scls">
{[...EMAIL, ...SOCIALS].map((n) => (
<SocialCard
url={n.url}
image={n.icon}
message={n.message}
></SocialCard>
))}
</div>
</DefaultSection>
</div>
<Footer></Footer>
</>;
</>
);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 915 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 771 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 897 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View file

@ -1,7 +1,7 @@
import * as ReactDom from "react-dom";
import * as React from "react";
import TopBar from "./components/TopBar";
import {ACTIVE_PAGES, SOCIALS, EMAIL, OFFICERS} from "./Config";
import { ACTIVE_PAGES, SOCIALS, EMAIL, OFFICERS } from "./Config";
import Splash from "./components/Splash";
import DefaultSection from "./components/DefaultSection";
import InvolveBox from "./components/InvolveBox";
@ -18,42 +18,89 @@ class Main extends React.Component<MainProps, MainState> {
this.state = {};
}
public render() {
return <>
return (
<>
<TopBar links={ACTIVE_PAGES}></TopBar>
<Splash cta="Join the 2nd largest IEEE student branch in the US!" delay={2000} backgrounds={["img/backgrounds/fa21qp.png"]}></Splash>
<Splash
cta="Join the 2nd largest IEEE student branch in the US!"
delay={2000}
backgrounds={["img/backgrounds/fa21qp.webp"]}
></Splash>
<div id="about-us">
<DefaultSection title="We are..." paragraphs={[
<DefaultSection
title="We are..."
paragraphs={[
"A diverse engineering community seeking to empower students through hands-on projects, networking opportunities, and social events. Bonus points on having an open-access project studio!",
"The Institute of Electrical and Electronics Engineers (IEEE) UC San Diego student branch is the second largest student chapter in the worlds largest professional organization. On the student level, we provide members with a plethora of ways to get involved!"
]}></DefaultSection>
"The Institute of Electrical and Electronics Engineers (IEEE) UC San Diego student branch is the second largest student chapter in the worlds largest professional organization. On the student level, we provide members with a plethora of ways to get involved!",
]}
></DefaultSection>
</div>
<div className="project-space">
<div className="ps-title">Join us at the Project Space!</div>
<p>The <a href="https://www.google.com/maps/@32.8817126,-117.2350998,59m/">IEEE Project Space</a> is an open-access, collaborative space where students can do homework or get access to basic electronic tools such as soldering stations, breadboard components, and Arduino and Raspberry PI parts!</p>
<a className="visit-us" href="https://www.google.com/maps/@32.8817126,-117.2350998,59m/">Come visit at EBU1-4710!</a>
<div className="ps-title">
Join us at the Project Space!
</div>
<DefaultSection className={"involved"} title="How else can I get involved?">
<p>
The{" "}
<a href="https://www.google.com/maps/@32.8817126,-117.2350998,59m/">
IEEE Project Space
</a>{" "}
is an open-access, collaborative space where students
can do homework or get access to basic electronic tools
such as soldering stations, breadboard components, and
Arduino and Raspberry PI parts!
</p>
<a
className="visit-us"
href="https://www.google.com/maps/@32.8817126,-117.2350998,59m/"
>
Come visit at EBU1-4710!
</a>
</div>
<DefaultSection
className={"involved"}
title="How else can I get involved?"
>
<div className="cards">
<InvolveBox boxTitle="Events" image="img/backgrounds/fa21social.png" description="Meet fellow IEEE members!"></InvolveBox>
<InvolveBox boxTitle="Projects" image="img/backgrounds/robofest.png" description="Learn new skills!"></InvolveBox>
<InvolveBox boxTitle="Committees" image="img/backgrounds/gbm.png" description="Build our amazing community!"></InvolveBox>
<InvolveBox
boxTitle="Events"
image="img/backgrounds/fa21social.webp"
description="Meet fellow IEEE members!"
></InvolveBox>
<InvolveBox
boxTitle="Projects"
image="img/backgrounds/robofest.webp"
description="Learn new skills!"
></InvolveBox>
<InvolveBox
boxTitle="Committees"
image="img/backgrounds/gbm.webp"
description="Build our amazing community!"
></InvolveBox>
</div>
</DefaultSection>
<div id="contact-us">
<DefaultSection title="Have questions? Contact us!">
<div className="join-scls">{
[...EMAIL, ...SOCIALS].map(n => (
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
))
}</div>
<div className="join-scls">
{[...EMAIL, ...SOCIALS].map((n) => (
<SocialCard
url={n.url}
image={n.icon}
message={n.message}
></SocialCard>
))}
</div>
</DefaultSection>
<DefaultSection className="contact" title="Or... Contact one of our staff!">
<DefaultSection
className="contact"
title="Or... Contact one of our staff!"
>
<Carousel items={OFFICERS} itemsPerPage={6}></Carousel>
</DefaultSection>
</div>
<Footer></Footer>
</>;
</>
);
}
}

View file

@ -1,7 +1,7 @@
import * as ReactDom from "react-dom";
import * as React from "react";
import TopBar from "./components/TopBar";
import {ACTIVE_PAGES, SOCIALS, EMAIL, OFFICERS} from "./Config";
import { ACTIVE_PAGES, SOCIALS, EMAIL, OFFICERS } from "./Config";
import Splash from "./components/Splash";
import DefaultSection from "./components/DefaultSection";
import InvolveBox from "./components/InvolveBox";
@ -18,40 +18,78 @@ class Main extends React.Component<MainProps, MainState> {
this.state = {};
}
public render() {
return <>
return (
<>
<TopBar links={ACTIVE_PAGES}></TopBar>
<Splash cta="Gain hands-on experience to make your resume stand out! No experience required!" delay={2000} backgrounds={["img/backgrounds/robocar.png"]}></Splash>
<DefaultSection title="RoboCup" paragraphs={[
"\"RoboCup is an international scientific initiative with the goal to advance the state of the art of intelligent robots. When established in 1997, the original mission was to field a team of robots capable of winning against the human soccer World Cup champions by 2050.\""
,"IEEE hosts Robocup Soccer, an annual project where teams develop six robots to compete with other teams during Robofest. Join this hands-on project to explore computer vision, mechanical design, and microcontroller development!"
]}>
<a className='ex-link' href='https://www.robocup.org/'>RoboCup website</a>
<Splash
cta="Gain hands-on experience to make your resume stand out! No experience required!"
delay={2000}
backgrounds={["img/backgrounds/robocar.webp"]}
></Splash>
<DefaultSection
title="RoboCup"
paragraphs={[
'"RoboCup is an international scientific initiative with the goal to advance the state of the art of intelligent robots. When established in 1997, the original mission was to field a team of robots capable of winning against the human soccer World Cup champions by 2050."',
"IEEE hosts Robocup Soccer, an annual project where teams develop six robots to compete with other teams during Robofest. Join this hands-on project to explore computer vision, mechanical design, and microcontroller development!",
]}
>
<a className="ex-link" href="https://www.robocup.org/">
RoboCup website
</a>
</DefaultSection>
<DefaultSection title="Quarterly Projects" paragraphs={[
"Getting started on hardware development or want to make your own project? IEEE's Quarterly Projects aims to provide students with project experience in a span of 10 weeks. During QP, students will acquire skills used in the industry such as C++ and the prototyping process with the assistance of our mentors."
]}>
<a className='ex-link' href='https://forms.gle/eW6e1i3vWCdBj7Vn6'>Apply here</a>
<DefaultSection
title="Quarterly Projects"
paragraphs={[
"Getting started on hardware development or want to make your own project? IEEE's Quarterly Projects aims to provide students with project experience in a span of 10 weeks. During QP, students will acquire skills used in the industry such as C++ and the prototyping process with the assistance of our mentors.",
]}
>
<a
className="ex-link"
href="https://forms.gle/eW6e1i3vWCdBj7Vn6"
>
Apply here
</a>
</DefaultSection>
<DefaultSection className={"past-proj"} title="Past Projects">
<div className="cards">
<InvolveBox boxTitle="" image="img/backgrounds/robocar.png" description="'22 Robocar Competition"></InvolveBox>
<InvolveBox boxTitle="" image="img/backgrounds/micromouse.png" description="'22 Micromouse Competition"></InvolveBox>
<InvolveBox boxTitle="" image="img/backgrounds/sp22qp.png" description="'22 Spring QP Showcase"></InvolveBox>
<InvolveBox
boxTitle=""
image="img/backgrounds/robocar.webp"
description="'22 Robocar Competition"
></InvolveBox>
<InvolveBox
boxTitle=""
image="img/backgrounds/micromouse.webp"
description="'22 Micromouse Competition"
></InvolveBox>
<InvolveBox
boxTitle=""
image="img/backgrounds/sp22qp.webp"
description="'22 Spring QP Showcase"
></InvolveBox>
</div>
</DefaultSection>
<div id="contact-us">
<DefaultSection className="contact" title="Have questions? Contact us!">
<div className="join-scls">{
[...EMAIL, ...SOCIALS].map(n => (
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
))
}</div>
<DefaultSection
className="contact"
title="Have questions? Contact us!"
>
<div className="join-scls">
{[...EMAIL, ...SOCIALS].map((n) => (
<SocialCard
url={n.url}
image={n.icon}
message={n.message}
></SocialCard>
))}
</div>
</DefaultSection>
</div>
<Footer></Footer>
</>;
</>
);
}
}

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>$TITLE</title>
<link rel="stylesheet" type="text/css" href="css/fonts.css" media="screen">
@ -9,8 +10,10 @@
<meta name="description" content="$DESCRIPTION">
<meta name="theme-color" content="$THEMECOLOR">
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="$JSFILE"></script>
<div id="root"></div>
<script type="text/javascript" src="$JSFILE"></script>
</body>
</html>

View file

@ -1,29 +1,30 @@
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
const LicensePlugin = require("license-webpack-plugin").LicenseWebpackPlugin;
const TerserPlugin = require('terser-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
const fs = require("fs");
module.exports = {
entry: loadEntries("./src/public"),
output: {
path: path.resolve(__dirname, "build/public"),
filename: "./js/[name].js"
filename: "./js/[name].js",
},
module: {
rules: [{
rules: [
{
test: /\.(tsx|ts)$/,
use: "ts-loader"
use: "ts-loader",
},
{
test: /\.(js)$/,
use: "babel-loader"
use: "babel-loader",
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
use: ["style-loader", "css-loader"],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
@ -31,18 +32,19 @@ module.exports = {
mode: "production",
plugins: [
new CopyPlugin({
patterns: [{
patterns: [
{
from: "./src/public",
to: ".",
globOptions: {
ignore: ["**/*.tsx", "**/*.ts"]
}
}
ignore: ["**/*.tsx", "**/*.ts"],
},
},
],
}),
new LicensePlugin({
outputFilename: 'third-party-notice.txt'
})
outputFilename: "third-party-notice.txt",
}),
],
optimization: {
minimize: true,
@ -58,12 +60,15 @@ module.exports = {
],
},
//devtool: "source-map"
devServer: {
static: "./build/public",
},
};
function loadEntries(dir) {
let files = fs.readdirSync(path.join(__dirname, dir));
let entries = {};
files.forEach(file => {
files.forEach((file) => {
let name = file.match(/^(.*)\.tsx$/);
if (name) {
entries[name[1]] = path.join(__dirname, dir, file);