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%
4
.prettierrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": false
|
||||||
|
}
|
29
README.md
|
@ -1,2 +1,27 @@
|
||||||
# NewWebsite
|
# IEEE @ UCSD Website
|
||||||
The new IEEE website for the section at UCSD
|
|
||||||
|
## 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
15
package.json
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"name": "ieee-website",
|
"name": "ieee-website",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "Website for IEEE of UC San Diego",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack & tsc & time /T",
|
"build": "webpack & tsc",
|
||||||
"watch": "npm-watch build"
|
"watch": "npm-watch build"
|
||||||
},
|
},
|
||||||
"watch": {
|
"watch": {
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
"@types/node": "^16.11.7",
|
"@types/node": "^16.11.7",
|
||||||
|
@ -35,14 +35,21 @@
|
||||||
"@babel/preset-env": "^7.15.8",
|
"@babel/preset-env": "^7.15.8",
|
||||||
"@babel/preset-react": "^7.14.5",
|
"@babel/preset-react": "^7.14.5",
|
||||||
"@types/react": "^16.14.20",
|
"@types/react": "^16.14.20",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.40.1",
|
||||||
"babel-loader": "^8.2.3",
|
"babel-loader": "^8.2.3",
|
||||||
"copy-webpack-plugin": "^6.4.1",
|
"copy-webpack-plugin": "^6.4.1",
|
||||||
"css-loader": "^5.2.7",
|
"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",
|
"html-webpack-plugin": "^4.5.2",
|
||||||
"license-webpack-plugin": "^2.3.21",
|
"license-webpack-plugin": "^2.3.21",
|
||||||
"style-loader": "^2.0.0",
|
"style-loader": "^2.0.0",
|
||||||
"ts-loader": "^8.3.0",
|
"ts-loader": "^8.3.0",
|
||||||
"typescript": "^4.4.4",
|
"typescript": "^4.8.4",
|
||||||
"webpack": "^5.60.0",
|
"webpack": "^5.60.0",
|
||||||
"webpack-cli": "^4.9.1"
|
"webpack-cli": "^4.9.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import {Schema, Document, LeanDocument} from "mongoose";
|
import { Schema, Document, LeanDocument } from "mongoose";
|
||||||
import * as mongoose from "mongoose";
|
import * as mongoose from "mongoose";
|
||||||
import {promisify} from "util";
|
import { promisify } from "util";
|
||||||
import {randomBytes, pbkdf2} from "crypto";
|
import { randomBytes, pbkdf2 } from "crypto";
|
||||||
|
|
||||||
const pbkdf = promisify(pbkdf2);
|
const pbkdf = promisify(pbkdf2);
|
||||||
|
|
||||||
const User = mongoose.model("User", new Schema({
|
const User = mongoose.model(
|
||||||
|
"User",
|
||||||
|
new Schema({
|
||||||
display: String,
|
display: String,
|
||||||
email: {
|
email: {
|
||||||
public: Boolean,
|
public: Boolean,
|
||||||
|
@ -14,19 +16,20 @@ const User = mongoose.model("User", new Schema({
|
||||||
picture: String,
|
picture: String,
|
||||||
password: {
|
password: {
|
||||||
hash: Buffer,
|
hash: Buffer,
|
||||||
salt: Buffer
|
salt: Buffer,
|
||||||
},
|
},
|
||||||
bio: {type: String, default: ""},
|
bio: { type: String, default: "" },
|
||||||
isOfficer: {type: Boolean, default: false},
|
isOfficer: { type: Boolean, default: false },
|
||||||
title: {type: String, default: "Member"},
|
title: { type: String, default: "Member" },
|
||||||
uuid: String
|
uuid: String,
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
export interface DBUser extends Document {
|
export interface DBUser extends Document {
|
||||||
display: string;
|
display: string;
|
||||||
email: string;
|
email: string;
|
||||||
picture: string;
|
picture: string;
|
||||||
password: HashSalt
|
password: HashSalt;
|
||||||
isOfficer: boolean;
|
isOfficer: boolean;
|
||||||
title: string;
|
title: string;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
@ -37,7 +40,6 @@ interface HashSalt {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class UserDatabase {
|
export default class UserDatabase {
|
||||||
|
|
||||||
// How many iterations pbkdf2 will iterate the password hashing algorithm
|
// How many iterations pbkdf2 will iterate the password hashing algorithm
|
||||||
private static PW_ITERATIONS = 100000;
|
private static PW_ITERATIONS = 100000;
|
||||||
// The length of the salt that should be used with every password hash
|
// 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
|
* @param newName the user's new name
|
||||||
*/
|
*/
|
||||||
public async setName(uuid: string, newName: string) {
|
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
|
* 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
|
* @returns the user's display name
|
||||||
*/
|
*/
|
||||||
public async getName(uuid: string): Promise<string> {
|
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
|
* @param newEmail the user's new display email
|
||||||
*/
|
*/
|
||||||
public async setEmail(uuid: string, newEmail: string) {
|
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
|
* Gets the email of a user with a given UUID
|
||||||
|
@ -86,7 +89,8 @@ export default class UserDatabase {
|
||||||
* @returns the user's email
|
* @returns the user's email
|
||||||
*/
|
*/
|
||||||
public async getEmail(uuid: string): Promise<string> {
|
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) {
|
public async setPassword(uuid: string, newPassword: string) {
|
||||||
let hashsalt = await UserDatabase.hash(newPassword);
|
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
|
* Gets the password of a user with a given UUID
|
||||||
|
@ -104,7 +111,8 @@ export default class UserDatabase {
|
||||||
* @returns the user's password
|
* @returns the user's password
|
||||||
*/
|
*/
|
||||||
public async getPasswordHash(uuid: string): Promise<Buffer> {
|
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
|
* @param newTitle the user's new officer title/position
|
||||||
*/
|
*/
|
||||||
public async setRank(uuid: string, newTitle: string, isOfficer: boolean) {
|
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
|
* Gets the title of a user with a given UUID
|
||||||
|
@ -121,7 +132,8 @@ export default class UserDatabase {
|
||||||
* @returns the user's title
|
* @returns the user's title
|
||||||
*/
|
*/
|
||||||
public async getRank(uuid: string): Promise<string> {
|
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
|
* 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
|
* @returns true if the user is an officer
|
||||||
*/
|
*/
|
||||||
public async isOfficer(uuid: string): Promise<boolean> {
|
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
|
* @param newPic the link to the new URL of the profile picture
|
||||||
*/
|
*/
|
||||||
public async setPicture(uuid: string, newPic: string) {
|
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
|
* 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
|
* @returns the user's profile picture
|
||||||
*/
|
*/
|
||||||
public async getPicture(uuid: string): Promise<string> {
|
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> {
|
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
|
// User creation and deletion functions
|
||||||
|
@ -159,7 +173,7 @@ export default class UserDatabase {
|
||||||
* @param uuid the UUID of the user
|
* @param uuid the UUID of the user
|
||||||
*/
|
*/
|
||||||
public async deleteUser(uuid: string) {
|
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 picture the user's picture
|
||||||
* @param password the user's plaintext password
|
* @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);
|
let encrypted = await UserDatabase.hash(password);
|
||||||
await (new User({
|
await new User({
|
||||||
display: display,
|
display: display,
|
||||||
email: email,
|
email: email,
|
||||||
picture: picture,
|
picture: picture,
|
||||||
password: encrypted,
|
password: encrypted,
|
||||||
uuid: UserDatabase.genUUID(),
|
uuid: UserDatabase.genUUID(),
|
||||||
isOfficer: !!isOfficer,
|
isOfficer: !!isOfficer,
|
||||||
title: title ? title : "Member"
|
title: title ? title : "Member",
|
||||||
})).save();
|
}).save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility functions
|
// Utility functions
|
||||||
|
@ -192,8 +213,14 @@ export default class UserDatabase {
|
||||||
let salt = randomBytes(UserDatabase.SALT_LENGTH);
|
let salt = randomBytes(UserDatabase.SALT_LENGTH);
|
||||||
let pass = Buffer.from(String.prototype.normalize(password));
|
let pass = Buffer.from(String.prototype.normalize(password));
|
||||||
return {
|
return {
|
||||||
hash: await pbkdf(pass, salt, UserDatabase.PW_ITERATIONS, 512, "sha512"),
|
hash: await pbkdf(
|
||||||
salt: salt
|
pass,
|
||||||
|
salt,
|
||||||
|
UserDatabase.PW_ITERATIONS,
|
||||||
|
512,
|
||||||
|
"sha512"
|
||||||
|
),
|
||||||
|
salt: salt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +230,7 @@ export default class UserDatabase {
|
||||||
*/
|
*/
|
||||||
public static genUUID(): string {
|
public static genUUID(): string {
|
||||||
return Array.from(randomBytes(UserDatabase.UUID_LENGTH))
|
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("");
|
||||||
}
|
}
|
||||||
}
|
}
|
74
src/index.ts
|
@ -1,5 +1,5 @@
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import {Request, Response} from "express";
|
import { Request, Response } from "express";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import UserDatabase from "./Database";
|
import UserDatabase from "./Database";
|
||||||
|
@ -14,77 +14,80 @@ interface Website {
|
||||||
themecolor: string;
|
themecolor: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = express();
|
const APP = express();
|
||||||
const template = fs.readFileSync(path.join(__dirname, "public/template.html")).toString();
|
const TEMPLATE = fs
|
||||||
const websites = [{
|
.readFileSync(path.join(__dirname, "public/template.html"))
|
||||||
|
.toString();
|
||||||
|
const WEBSITES = [
|
||||||
|
{
|
||||||
sitename: "index",
|
sitename: "index",
|
||||||
title: "IEEE at UCSD",
|
title: "IEEE at UCSD",
|
||||||
description: "",
|
description: "",
|
||||||
jsfile: "js/index.js",
|
jsfile: "js/index.js",
|
||||||
cssfile: "css/styles.css",
|
cssfile: "css/styles.css",
|
||||||
themecolor: ""
|
themecolor: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sitename: "events",
|
sitename: "events",
|
||||||
title: "IEEE at UCSD",
|
title: "IEEE at UCSD",
|
||||||
description: "",
|
description: "",
|
||||||
jsfile: "js/events.js",
|
jsfile: "js/events.js",
|
||||||
cssfile: "css/styles.css",
|
cssfile: "css/styles.css",
|
||||||
themecolor: ""
|
themecolor: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sitename: "projects",
|
sitename: "projects",
|
||||||
title: "IEEE at UCSD",
|
title: "IEEE at UCSD",
|
||||||
description: "",
|
description: "",
|
||||||
jsfile: "js/projects.js",
|
jsfile: "js/projects.js",
|
||||||
cssfile: "css/styles.css",
|
cssfile: "css/styles.css",
|
||||||
themecolor: ""
|
themecolor: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sitename: "committees",
|
sitename: "committees",
|
||||||
title: "IEEE at UCSD",
|
title: "IEEE at UCSD",
|
||||||
description: "",
|
description: "",
|
||||||
jsfile: "js/committees.js",
|
jsfile: "js/committees.js",
|
||||||
cssfile: "css/styles.css",
|
cssfile: "css/styles.css",
|
||||||
themecolor: ""
|
themecolor: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sitename: "contact",
|
sitename: "contact",
|
||||||
title: "IEEE at UCSD",
|
title: "IEEE at UCSD",
|
||||||
description: "",
|
description: "",
|
||||||
jsfile: "js/index.js",
|
jsfile: "js/index.js",
|
||||||
cssfile: "css/styles.css",
|
cssfile: "css/styles.css",
|
||||||
themecolor: ""
|
themecolor: "",
|
||||||
}
|
},
|
||||||
] as Website[];
|
] as Website[];
|
||||||
|
|
||||||
const PORT = 9000;
|
const PORT = 9000;
|
||||||
|
|
||||||
// Make the public directory traversible to people online
|
// 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
|
// 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;
|
req.cookies = req.headers.cookie;
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
// Receive json post requests and urlencoded requests
|
// Receive json post requests and urlencoded requests
|
||||||
app.use(express.json());
|
APP.use(express.json());
|
||||||
app.use(express.urlencoded({extended: true}));
|
APP.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
// Send main page
|
// Send main page
|
||||||
app.get("/", (req: Request, res: Response) => {
|
APP.get("/", (req: Request, res: Response) => {
|
||||||
respond(res, "index");
|
respond(res, "index");
|
||||||
});
|
});
|
||||||
app.get("/events", (req: Request, res: Response) => {
|
APP.get("/events", (req: Request, res: Response) => {
|
||||||
respond(res, "events");
|
respond(res, "events");
|
||||||
});
|
});
|
||||||
app.get("/projects", (req: Request, res: Response) => {
|
APP.get("/projects", (req: Request, res: Response) => {
|
||||||
respond(res, "projects");
|
respond(res, "projects");
|
||||||
});
|
});
|
||||||
app.get("/committees", (req: Request, res: Response) => {
|
APP.get("/committees", (req: Request, res: Response) => {
|
||||||
respond(res, "committees");
|
respond(res, "committees");
|
||||||
});
|
});
|
||||||
app.get("/contact", (req: Request, res: Response) => {
|
APP.get("/contact", (req: Request, res: Response) => {
|
||||||
respond(res, "contact");
|
respond(res, "contact");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -93,14 +96,14 @@ app.get("/contact", (req: Request, res: Response) => {
|
||||||
*/
|
*/
|
||||||
function respond(res: any, filename: string) {
|
function respond(res: any, filename: string) {
|
||||||
res.set({
|
res.set({
|
||||||
"Content-Type": "text/html"
|
"Content-Type": "text/html",
|
||||||
});
|
});
|
||||||
res.send(generatePage(filename));
|
res.send(generatePage(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
function generatePage(name: string): string {
|
function generatePage(name: string): string {
|
||||||
let site = websites.find(e=>e.sitename===name);
|
let site = WEBSITES.find((e) => e.sitename === name);
|
||||||
let html = template;
|
let html = TEMPLATE;
|
||||||
for (let key of Object.keys(site)) {
|
for (let key of Object.keys(site)) {
|
||||||
html = html.replace(new RegExp("\\$" + key.toUpperCase()), site[key]);
|
html = html.replace(new RegExp("\\$" + key.toUpperCase()), site[key]);
|
||||||
}
|
}
|
||||||
|
@ -108,14 +111,19 @@ function generatePage(name: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateFilePages() {
|
function generateFilePages() {
|
||||||
for (let site of websites) {
|
for (let site of WEBSITES) {
|
||||||
let html = generatePage(site.sitename);
|
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") {
|
if (process.argv[2] === "generate") {
|
||||||
generateFilePages();
|
generateFilePages();
|
||||||
} else {
|
} else {
|
||||||
app.listen(PORT, "127.0.0.1");
|
APP.listen(PORT, () => {
|
||||||
|
console.log(`Listening on port ${PORT}`);
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -1,171 +1,237 @@
|
||||||
// The links that are on the top nav bar that link to a lowercase version of their page
|
// 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",
|
name: "Home",
|
||||||
url: "/"
|
url: "/",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "Events",
|
name: "Events",
|
||||||
url: "/events"
|
url: "/events",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "Projects",
|
name: "Projects",
|
||||||
url: "/projects"
|
url: "/projects",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "Committees",
|
name: "Committees",
|
||||||
url: "/committees"
|
url: "/committees",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "Contact Us",
|
name: "Contact Us",
|
||||||
url: "/contact"
|
url: "/contact",
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
|
|
||||||
// Urls of team photos that will go in the "About" slideshow
|
// Urls of team photos that will go in the "About" slideshow
|
||||||
export const TEAM_PHOTOS: string[] = [];
|
export const TEAM_PHOTOS: string[] = [];
|
||||||
export const PROJECT_SPACE: string[] = [];
|
export const PROJECT_SPACE: string[] = [];
|
||||||
export const EVENTS: any[] = [];
|
export const EVENTS: any[] = [];
|
||||||
|
|
||||||
|
export const SOCIALS = [
|
||||||
export const SOCIALS = [{
|
{
|
||||||
icon: "img/disc.svg",
|
icon: "img/disc.svg",
|
||||||
url: "https://discord.gg/XxfjqZSjca",
|
url: "https://discord.gg/XxfjqZSjca",
|
||||||
message: "Join our server"
|
message: "Join our server",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
icon: "img/fab.svg",
|
icon: "img/fab.svg",
|
||||||
url: "https://www.facebook.com/ieeeucsd",
|
url: "https://www.facebook.com/ieeeucsd",
|
||||||
message: "ieeeucsd"
|
message: "ieeeucsd",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
icon: "img/inst.svg",
|
icon: "img/inst.svg",
|
||||||
url: "https://www.instagram.com/ieee.ucsd",
|
url: "https://www.instagram.com/ieee.ucsd",
|
||||||
message: "@ieeeucsd"
|
message: "@ieeeucsd",
|
||||||
}];
|
},
|
||||||
export const EMAIL = [{
|
];
|
||||||
|
export const EMAIL = [
|
||||||
|
{
|
||||||
icon: "img/email.svg",
|
icon: "img/email.svg",
|
||||||
url: "mailto:ieee@eng.ucsd.edu",
|
url: "mailto:ieee@eng.ucsd.edu",
|
||||||
message: "ieee@eng.ucsd.edu"
|
message: "ieee@eng.ucsd.edu",
|
||||||
}];
|
},
|
||||||
export const EMAIL_WHITE = [{
|
];
|
||||||
|
export const EMAIL_WHITE = [
|
||||||
|
{
|
||||||
icon: "img/email_white.svg",
|
icon: "img/email_white.svg",
|
||||||
url: "mailto:ieee@eng.ucsd.edu",
|
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",
|
icon: "img/disc_white.svg",
|
||||||
url: "https://discord.gg/XxfjqZSjca",
|
url: "https://discord.gg/XxfjqZSjca",
|
||||||
message: "Join our server"
|
message: "Join our server",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
icon: "img/fab_white.svg",
|
icon: "img/fab_white.svg",
|
||||||
url: "https://www.facebook.com/ieeeucsd",
|
url: "https://www.facebook.com/ieeeucsd",
|
||||||
message: "ieeeucsd"
|
message: "ieeeucsd",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
icon: "img/inst_white.svg",
|
icon: "img/inst_white.svg",
|
||||||
url: "https://www.instagram.com/ieee.ucsd",
|
url: "https://www.instagram.com/ieee.ucsd",
|
||||||
message: "@ieeeucsd"
|
message: "@ieeeucsd",
|
||||||
}];
|
},
|
||||||
export const OFFICERS = [{
|
];
|
||||||
|
|
||||||
|
export const OFFICERS = [
|
||||||
|
{
|
||||||
name: "Darin Tsui",
|
name: "Darin Tsui",
|
||||||
position: "Chair",
|
position: "Chair",
|
||||||
photo: "img/officers/darin.jpg",
|
photo: "img/officers/darin.jpg",
|
||||||
email: "email@ucsd.edu"
|
email: "email@ucsd.edu",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "Brigette Hacia",
|
name: "Brigette Hacia",
|
||||||
position: "Vice Chair Internal",
|
position: "Vice Chair Internal",
|
||||||
photo: "img/officers/brigette.jpg",
|
photo: "img/officers/brigette.jpg",
|
||||||
email: "email@ucsd.edu"
|
email: "email@ucsd.edu",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "Tasnia Jamal",
|
name: "Tasnia Jamal",
|
||||||
position: "Vice Chair Events",
|
position: "Vice Chair Events",
|
||||||
photo: "img/officers/tasnia.jpg",
|
photo: "img/officers/tasnia.jpg",
|
||||||
email: "email@ucsd.edu"
|
email: "email@ucsd.edu",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "Kevin Chang",
|
name: "Kevin Chang",
|
||||||
position: "Vice Chair Projects",
|
position: "Vice Chair Projects",
|
||||||
photo: "img/officers/kevin.jpg",
|
photo: "img/officers/kevin.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: "Arjun Sampath",
|
name: "Arjun Sampath",
|
||||||
position: "Vice Chair Finance",
|
position: "Vice Chair Finance",
|
||||||
photo: "img/officers/arjun.jpg",
|
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",
|
name: "Derek Nguyen",
|
||||||
position: "Project Space Chair",
|
position: "Project Space Chair",
|
||||||
photo: "img/officers/derek.jpg",
|
photo: "img/officers/derek.jpg",
|
||||||
email: "email@ucsd.edu"
|
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"
|
|
||||||
}, {
|
|
||||||
name: "Rafaella Gomes",
|
name: "Rafaella Gomes",
|
||||||
position: "Robocup Chair",
|
position: "Robocup Chair",
|
||||||
photo: "img/officers/rafaella.jpg",
|
photo: "img/officers/rafaella.jpg",
|
||||||
email: "email@ucsd.edu"
|
email: "email@ucsd.edu",
|
||||||
}, {
|
},
|
||||||
name: "Josh Lapidario",
|
{
|
||||||
position: "Quarterly Projects Chair",
|
name: "Yash Puneet",
|
||||||
photo: "img/officers/josh.jpg",
|
position: "Robocup Chair",
|
||||||
email: "email@ucsd.edu"
|
photo: "img/officers/yash.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"
|
|
||||||
}, {
|
|
||||||
name: "Matthew Mikhailov",
|
name: "Matthew Mikhailov",
|
||||||
position: "Supercomputing Chair",
|
position: "Supercomputing Chair",
|
||||||
photo: "img/officers/temp.png",
|
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",
|
name: "Raymond Wang",
|
||||||
position: "Webmaster",
|
position: "Webmaster",
|
||||||
photo: "img/officers/temp.png",
|
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",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as ReactDom from "react-dom";
|
import * as ReactDom from "react-dom";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import TopBar from "./components/TopBar";
|
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 Splash from "./components/Splash";
|
||||||
import DefaultSection from "./components/DefaultSection";
|
import DefaultSection from "./components/DefaultSection";
|
||||||
import InvolveBox from "./components/InvolveBox";
|
import InvolveBox from "./components/InvolveBox";
|
||||||
|
@ -18,38 +18,73 @@ class Main extends React.Component<MainProps, MainState> {
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return <>
|
return (
|
||||||
|
<>
|
||||||
<TopBar links={ACTIVE_PAGES}></TopBar>
|
<TopBar links={ACTIVE_PAGES}></TopBar>
|
||||||
<Splash cta="The backbone of IEEE. Come help make a difference!" delay={2000} backgrounds={["img/backgrounds/committee.png"]}></Splash>
|
<Splash
|
||||||
<DefaultSection title="Join us!" paragraphs={[
|
cta="The backbone of IEEE. Come help make a difference!"
|
||||||
"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!"
|
delay={2000}
|
||||||
]}>
|
backgrounds={["img/backgrounds/committee.webp"]}
|
||||||
</DefaultSection>
|
></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">
|
<DefaultSection className={"our-comms"} title="Our Committees">
|
||||||
<div className="cards">
|
<div className="cards">
|
||||||
<InvolveBox boxTitle="" image="img/committees/technical.jpg" description="Technical Committee"></InvolveBox>
|
<InvolveBox
|
||||||
<InvolveBox boxTitle="" image="img/committees/social.jpg" description="Social Committee"></InvolveBox>
|
boxTitle=""
|
||||||
<InvolveBox boxTitle="" image="img/committees/professional.jpg" description="Professional Committee"></InvolveBox>
|
image="img/committees/technical.webp"
|
||||||
<InvolveBox boxTitle="" image="img/committees/pr.jpg" description="PR Committee"></InvolveBox>
|
description="Technical Committee"
|
||||||
<InvolveBox boxTitle="" image="img/committees/outreach.jpg" description="Outreach Committee"></InvolveBox>
|
></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>
|
</div>
|
||||||
</DefaultSection>
|
</DefaultSection>
|
||||||
|
|
||||||
<div id="contact-us">
|
<div id="contact-us">
|
||||||
<DefaultSection title="Interested? Join our socials!">
|
<DefaultSection title="Interested? Join our socials!">
|
||||||
<div className="join-scls">{
|
<div className="join-scls">
|
||||||
[...EMAIL, ...SOCIALS].map(n => (
|
{[...EMAIL, ...SOCIALS].map((n) => (
|
||||||
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
|
<SocialCard
|
||||||
))
|
url={n.url}
|
||||||
}</div>
|
image={n.icon}
|
||||||
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</DefaultSection>
|
</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>
|
<Carousel items={OFFICERS} itemsPerPage={6}></Carousel>
|
||||||
</DefaultSection>
|
</DefaultSection>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</>;
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
import { CarouselItemProps } from "./CarouselItem";
|
import { CarouselItemProps } from "./CarouselItem";
|
||||||
import CarouselPage from "./CarouselPage";
|
import CarouselPage from "./CarouselPage";
|
||||||
|
|
||||||
|
@ -15,41 +15,65 @@ export default class Carousel extends Component<CarouselProps, CarouselState> {
|
||||||
constructor(props: CarouselProps) {
|
constructor(props: CarouselProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
page: 0
|
page: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private prevPage() {
|
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() {
|
private nextPage() {
|
||||||
this.setState({ page: this.state.page + 1 > Math.ceil(this.props.items.length / this.props.itemsPerPage) - 1 ?
|
this.setState({
|
||||||
Math.ceil(this.props.items.length / this.props.itemsPerPage) - 1 :
|
page:
|
||||||
this.state.page + 1
|
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() {
|
public render() {
|
||||||
let arr = this.chunkArray(this.props.items);
|
let arr = this.chunkArray(this.props.items);
|
||||||
return <div className="carousel">
|
return (
|
||||||
<img className="carousel-left" src="img/arrow.svg" style={
|
<div className="carousel">
|
||||||
this.state.page === 0 ? {visibility: "hidden"} : {}
|
<img
|
||||||
} onClick={this.prevPage.bind(this)}></img>
|
className="carousel-left"
|
||||||
<div className="carousel-items">{
|
src="img/arrow.svg"
|
||||||
arr.map((items, i)=>(
|
style={
|
||||||
<CarouselPage items={items} visible={i===this.state.page}></CarouselPage>
|
this.state.page === 0 ? { visibility: "hidden" } : {}
|
||||||
))
|
}
|
||||||
}</div>
|
onClick={this.prevPage.bind(this)}
|
||||||
<img className="carousel-right" src="img/arrow.svg" style={
|
></img>
|
||||||
this.state.page === arr.length - 1 ? {visibility: "hidden"} : {}
|
<div className="carousel-items">
|
||||||
} onClick={this.nextPage.bind(this)}></img>
|
{arr.map((items, i) => (
|
||||||
</div>;
|
<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[][];
|
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));
|
returnArr.push(array.slice(i, i + this.props.itemsPerPage));
|
||||||
}
|
}
|
||||||
return returnArr;
|
return returnArr;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
|
|
||||||
export interface CarouselItemProps {
|
export interface CarouselItemProps {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -9,17 +9,22 @@ export interface CarouselItemProps {
|
||||||
}
|
}
|
||||||
interface CarouselItemState {}
|
interface CarouselItemState {}
|
||||||
|
|
||||||
export default class CarouselItem extends Component<CarouselItemProps, CarouselItemState> {
|
export default class CarouselItem extends Component<
|
||||||
|
CarouselItemProps,
|
||||||
|
CarouselItemState
|
||||||
|
> {
|
||||||
constructor(props: CarouselItemProps) {
|
constructor(props: CarouselItemProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className="carousel-item">
|
return (
|
||||||
|
<div className="carousel-item">
|
||||||
<img src={this.props.photo}></img>
|
<img src={this.props.photo}></img>
|
||||||
<div className="carousel-name">{this.props.name}</div>
|
<div className="carousel-name">{this.props.name}</div>
|
||||||
<div className="carousel-pos">{this.props.position}</div>
|
<div className="carousel-pos">{this.props.position}</div>
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
import CarouselItem, { CarouselItemProps } from "./CarouselItem";
|
import CarouselItem, { CarouselItemProps } from "./CarouselItem";
|
||||||
|
|
||||||
interface CarouselPageProps {
|
interface CarouselPageProps {
|
||||||
|
@ -8,17 +8,25 @@ interface CarouselPageProps {
|
||||||
}
|
}
|
||||||
interface CarouselPageState {}
|
interface CarouselPageState {}
|
||||||
|
|
||||||
export default class CarouselPage extends Component<CarouselPageProps, CarouselPageState> {
|
export default class CarouselPage extends Component<
|
||||||
|
CarouselPageProps,
|
||||||
|
CarouselPageState
|
||||||
|
> {
|
||||||
constructor(props: CarouselPageProps) {
|
constructor(props: CarouselPageProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className="carousel-page" style={this.props.visible ? {} : {display: "none"}}>{
|
return (
|
||||||
this.props.items.map(n=>(
|
<div
|
||||||
|
className="carousel-page"
|
||||||
|
style={this.props.visible ? {} : { display: "none" }}
|
||||||
|
>
|
||||||
|
{this.props.items.map((n) => (
|
||||||
<CarouselItem {...n}></CarouselItem>
|
<CarouselItem {...n}></CarouselItem>
|
||||||
))
|
))}
|
||||||
}</div>;
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
|
|
||||||
interface DefaultSectionProps {
|
interface DefaultSectionProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -8,19 +8,30 @@ interface DefaultSectionProps {
|
||||||
}
|
}
|
||||||
interface DefaultSectionState {}
|
interface DefaultSectionState {}
|
||||||
|
|
||||||
export default class DefaultSection extends Component<DefaultSectionProps, DefaultSectionState> {
|
export default class DefaultSection extends Component<
|
||||||
|
DefaultSectionProps,
|
||||||
|
DefaultSectionState
|
||||||
|
> {
|
||||||
constructor(props: DefaultSectionProps) {
|
constructor(props: DefaultSectionProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
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>
|
<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>
|
<p>{n}</p>
|
||||||
))}
|
)
|
||||||
|
)}
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
import SocialCard from "./SocialCard";
|
import SocialCard from "./SocialCard";
|
||||||
import {EMAIL_WHITE, SOCIALS_WHITE} from "../Config";
|
import { EMAIL_WHITE, SOCIALS_WHITE } from "../Config";
|
||||||
|
|
||||||
interface FooterProps {}
|
interface FooterProps {}
|
||||||
interface FooterState {}
|
interface FooterState {}
|
||||||
|
@ -13,13 +13,19 @@ export default class Footer extends Component<FooterProps, FooterState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className="footer">
|
return (
|
||||||
|
<div className="footer">
|
||||||
<img src="img/logo_white.svg"></img>
|
<img src="img/logo_white.svg"></img>
|
||||||
<div className="footer-scls">{
|
<div className="footer-scls">
|
||||||
[...EMAIL_WHITE, ...SOCIALS_WHITE].map(n => (
|
{[...EMAIL_WHITE, ...SOCIALS_WHITE].map((n) => (
|
||||||
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
|
<SocialCard
|
||||||
))
|
url={n.url}
|
||||||
}</div>
|
image={n.icon}
|
||||||
</div>;
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
|
|
||||||
interface InvolveBoxProps {
|
interface InvolveBoxProps {
|
||||||
boxTitle: string;
|
boxTitle: string;
|
||||||
|
@ -8,17 +8,29 @@ interface InvolveBoxProps {
|
||||||
}
|
}
|
||||||
interface InvolveBoxState {}
|
interface InvolveBoxState {}
|
||||||
|
|
||||||
export default class InvolveBox extends Component<InvolveBoxProps, InvolveBoxState> {
|
export default class InvolveBox extends Component<
|
||||||
|
InvolveBoxProps,
|
||||||
|
InvolveBoxState
|
||||||
|
> {
|
||||||
constructor(props: InvolveBoxProps) {
|
constructor(props: InvolveBoxProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className="involve-card">
|
return (
|
||||||
<a className="involve-title" href={"/"+this.props.boxTitle.toLowerCase()}>{this.props.boxTitle}</a>
|
<div className="involve-card">
|
||||||
|
<a
|
||||||
|
className="involve-title"
|
||||||
|
href={"/" + this.props.boxTitle.toLowerCase()}
|
||||||
|
>
|
||||||
|
{this.props.boxTitle}
|
||||||
|
</a>
|
||||||
<img src={this.props.image}></img>
|
<img src={this.props.image}></img>
|
||||||
<div className="involve-description">{this.props.description}</div>
|
<div className="involve-description">
|
||||||
</div>;
|
{this.props.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
|
|
||||||
interface SocialCardProps {
|
interface SocialCardProps {
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -8,16 +8,21 @@ interface SocialCardProps {
|
||||||
}
|
}
|
||||||
interface SocialCardState {}
|
interface SocialCardState {}
|
||||||
|
|
||||||
export default class SocialCard extends Component<SocialCardProps, SocialCardState> {
|
export default class SocialCard extends Component<
|
||||||
|
SocialCardProps,
|
||||||
|
SocialCardState
|
||||||
|
> {
|
||||||
constructor(props: SocialCardProps) {
|
constructor(props: SocialCardProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
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>
|
<img src={this.props.image}></img>
|
||||||
<div className="social-message">{this.props.message}</div>
|
<div className="social-message">{this.props.message}</div>
|
||||||
</a>;
|
</a>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
import {SOCIALS_WHITE} from "../Config";
|
import { SOCIALS_WHITE } from "../Config";
|
||||||
|
|
||||||
interface SplashProps {
|
interface SplashProps {
|
||||||
cta: string;
|
cta: string;
|
||||||
|
@ -16,31 +16,41 @@ export default class Splash extends Component<SplashProps, SplashState> {
|
||||||
constructor(props: SplashProps) {
|
constructor(props: SplashProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
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 {
|
private changeImage(): void {
|
||||||
if (this.state.progress < this.props.backgrounds.length - 1) {
|
if (this.state.progress < this.props.backgrounds.length - 1) {
|
||||||
this.setState({progress: this.state.progress + 1});
|
this.setState({ progress: this.state.progress + 1 });
|
||||||
} else {
|
} else {
|
||||||
this.setState({progress: 0});
|
this.setState({ progress: 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className="splash" style={{
|
return (
|
||||||
backgroundImage: `url("${this.props.backgrounds[this.state.progress]}")`
|
<div
|
||||||
}}>
|
className="splash"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url("${
|
||||||
|
this.props.backgrounds[this.state.progress]
|
||||||
|
}")`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="call-to-action">{this.props.cta}</div>
|
<div className="call-to-action">{this.props.cta}</div>
|
||||||
<div className="splash-socials">{
|
<div className="splash-socials">
|
||||||
SOCIALS_WHITE.map(n=>(
|
{SOCIALS_WHITE.map((n) => (
|
||||||
<a href={n.url} key={n.icon}>
|
<a href={n.url} key={n.icon}>
|
||||||
<img src={n.icon}></img>
|
<img src={n.icon}></img>
|
||||||
</a>
|
</a>
|
||||||
))
|
))}
|
||||||
}</div>
|
</div>
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
|
|
||||||
interface TopBarProps {
|
interface TopBarProps {
|
||||||
links: {
|
links: {
|
||||||
|
@ -18,42 +18,65 @@ export default class TopBar extends Component<TopBarProps, TopBarState> {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
showBurger: this.shouldShowBurger(),
|
showBurger: this.shouldShowBurger(),
|
||||||
menuVisible: false
|
menuVisible: false,
|
||||||
};
|
};
|
||||||
window.addEventListener("resize", this.checkResize.bind(this));
|
window.addEventListener("resize", this.checkResize.bind(this));
|
||||||
}
|
}
|
||||||
private toggleMenu() {
|
private toggleMenu() {
|
||||||
this.setState({menuVisible: !this.state.menuVisible});
|
this.setState({ menuVisible: !this.state.menuVisible });
|
||||||
}
|
}
|
||||||
private checkResize() {
|
private checkResize() {
|
||||||
this.setState({showBurger: this.shouldShowBurger()});
|
this.setState({ showBurger: this.shouldShowBurger() });
|
||||||
}
|
}
|
||||||
private shouldShowBurger(): boolean {
|
private shouldShowBurger(): boolean {
|
||||||
return window.innerWidth < TopBar.HAMBURGER_POINT;
|
return window.innerWidth < TopBar.HAMBURGER_POINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className={`topbar${
|
return (
|
||||||
|
<div
|
||||||
|
className={`topbar${
|
||||||
this.state.showBurger ? " burger-bar" : ""
|
this.state.showBurger ? " burger-bar" : ""
|
||||||
}`}>
|
}`}
|
||||||
|
>
|
||||||
<div className="img-cont">
|
<div className="img-cont">
|
||||||
<a href="/"><img src="img/logo.svg"></img></a>
|
<a href="/">
|
||||||
<div className="burger" style={{
|
<img src="img/logo.svg"></img>
|
||||||
display: this.state.showBurger ? "initial" : "none"
|
</a>
|
||||||
}} onClick={this.toggleMenu.bind(this)} role="menubar">≡</div>
|
<div
|
||||||
|
className="burger"
|
||||||
|
style={{
|
||||||
|
display: this.state.showBurger ? "initial" : "none",
|
||||||
|
}}
|
||||||
|
onClick={this.toggleMenu.bind(this)}
|
||||||
|
role="menubar"
|
||||||
|
>
|
||||||
|
≡
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="links">
|
<div className="links">
|
||||||
|
<div
|
||||||
<div className={`link-items${
|
className={`link-items${
|
||||||
this.state.showBurger ? " burger-time" : ""
|
this.state.showBurger ? " burger-time" : ""
|
||||||
}`} style={{display: this.state.showBurger ?
|
}`}
|
||||||
(this.state.menuVisible ? "flex" : "none") :
|
style={{
|
||||||
"initial"}}>{
|
display: this.state.showBurger
|
||||||
this.props.links.map(l=>{
|
? this.state.menuVisible
|
||||||
return <a className="navlink" href={l.url}>{l.name}</a>
|
? "flex"
|
||||||
})
|
: "none"
|
||||||
}</div>
|
: "initial",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{this.props.links.map((l) => {
|
||||||
|
return (
|
||||||
|
<a className="navlink" href={l.url}>
|
||||||
|
{l.name}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
url('../fonts/roboto-v29-latin-700.woff') format('woff');
|
url('../fonts/roboto-v29-latin-700.woff') format('woff');
|
||||||
/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* montserrat-regular - latin */
|
/* montserrat-regular - latin */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Montserrat';
|
font-family: 'Montserrat';
|
||||||
|
|
|
@ -1,29 +1,34 @@
|
||||||
/* Color vars should go here */
|
/* Global CSS Properties */
|
||||||
:root {
|
:root {
|
||||||
--main: #00629B;
|
--main: #00629b;
|
||||||
--accent: #FFCD00;
|
--accent: #ffcd00;
|
||||||
--secondary: white;
|
--secondary: #ffffff;
|
||||||
--dark: #2A1A4E;
|
--dark: #2a1a4e;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
scrollbar-width: auto;
|
scrollbar-width: auto;
|
||||||
scrollbar-color: var(--main) transparent;
|
scrollbar-color: var(--main) transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar {
|
*::-webkit-scrollbar {
|
||||||
width: 0.6em;
|
width: 0.6em;
|
||||||
height: 0.6em;
|
height: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar-track {
|
*::-webkit-scrollbar-track {
|
||||||
background: var(--main);
|
background: var(--main);
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar-thumb {
|
*::-webkit-scrollbar-thumb {
|
||||||
background-color: var(--secondary);
|
background-color: var(--secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-family: "Roboto", sans-serif;
|
font-family: "Roboto", sans-serif;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +46,7 @@ a:hover {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar {
|
.topbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -50,20 +56,24 @@ a:hover {
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar.burger-bar {
|
.topbar.burger-bar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.topbar.burger-bar > .img-cont {
|
|
||||||
|
.topbar.burger-bar>.img-cont {
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img-cont img {
|
.img-cont img {
|
||||||
width: 22em;
|
width: 22em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.burger {
|
.burger {
|
||||||
font-size: 2.8em;
|
font-size: 2.8em;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
@ -71,26 +81,31 @@ a:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-right: 0.3em;
|
margin-right: 0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-items.burger-time {
|
.link-items.burger-time {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: var(--secondary);
|
background-color: var(--secondary);
|
||||||
width: 10em;
|
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;
|
right: 0;
|
||||||
margin-top: 0.36em;
|
margin-top: 0.36em;
|
||||||
}
|
}
|
||||||
.link-items.burger-time > a {
|
|
||||||
|
.link-items.burger-time>a {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.4em 0.75em;
|
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 {
|
.navlink {
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
margin: 0.75em;
|
margin: 0.75em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.splash {
|
.splash {
|
||||||
background-color: var(--main);
|
background-color: var(--main);
|
||||||
background-blend-mode: overlay;
|
background-blend-mode: overlay;
|
||||||
|
@ -104,6 +119,7 @@ a:hover {
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.call-to-action {
|
.call-to-action {
|
||||||
font-size: 3.2em;
|
font-size: 3.2em;
|
||||||
width: 11em;
|
width: 11em;
|
||||||
|
@ -111,16 +127,20 @@ a:hover {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: "Montserrat";
|
font-family: "Montserrat";
|
||||||
}
|
}
|
||||||
|
|
||||||
.splash-socials {
|
.splash-socials {
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
}
|
}
|
||||||
.splash-socials > a {
|
|
||||||
|
.splash-socials>a {
|
||||||
margin-left: 1.5em;
|
margin-left: 1.5em;
|
||||||
margin-right: 1.5em;
|
margin-right: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.splash-socials img {
|
.splash-socials img {
|
||||||
width: 4.7em;
|
width: 4.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.default-section {
|
.default-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -131,28 +151,34 @@ a:hover {
|
||||||
padding-top: 2em;
|
padding-top: 2em;
|
||||||
padding-bottom: 2em;
|
padding-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
margin-top: 0.8em;
|
margin-top: 0.8em;
|
||||||
margin-bottom: 0.8em;
|
margin-bottom: 0.8em;
|
||||||
}
|
}
|
||||||
.default-section > p, .project-space > p {
|
|
||||||
|
.default-section>p,
|
||||||
|
.project-space>p {
|
||||||
font-size: 1.8em;
|
font-size: 1.8em;
|
||||||
width: 22em;
|
width: 22em;
|
||||||
color: var(--dark);
|
color: var(--dark);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.project-space > p {
|
|
||||||
|
.project-space>p {
|
||||||
color: var(--secondary);
|
color: var(--secondary);
|
||||||
}
|
}
|
||||||
.default-section > p:first-child {
|
|
||||||
|
.default-section>p:first-child {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-space {
|
.project-space {
|
||||||
border-radius: 50% 50% 0 0 / 4rem;
|
border-radius: 50% 50% 0 0 / 4rem;
|
||||||
background-color: var(--main);
|
background-color: var(--main);
|
||||||
background-blend-mode: overlay;
|
background-blend-mode: overlay;
|
||||||
background-image: url("../img/backgrounds/ps.png");
|
background-image: url("../img/backgrounds/ps.webp");
|
||||||
height: 40em;
|
height: 40em;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -161,32 +187,39 @@ a:hover {
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-space a {
|
.project-space a {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ps-title {
|
.ps-title {
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
color: white;
|
color: white;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.visit-us {
|
.visit-us {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ex-link {
|
.ex-link {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.involved {
|
.involved {
|
||||||
border-radius: 50% 50% 0 0 / 4rem;
|
border-radius: 50% 50% 0 0 / 4rem;
|
||||||
transform: translateY(-4rem);
|
transform: translateY(-4rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cards {
|
.cards {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.involve-card {
|
.involve-card {
|
||||||
padding: 1.75em 2.5em;
|
padding: 1.75em 2.5em;
|
||||||
border: var(--main) solid 0.37em;
|
border: var(--main) solid 0.37em;
|
||||||
|
@ -198,32 +231,41 @@ a:hover {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.involve-title {
|
.involve-title {
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
color: var(--main);
|
color: var(--main);
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
.involve-card > img {
|
|
||||||
|
.involve-card>img {
|
||||||
width: 20em;
|
width: 20em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
border-radius: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.links {
|
.links {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.social-card {
|
.social-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
width: 25em;
|
width: 25em;
|
||||||
}
|
}
|
||||||
.social-card > img {
|
|
||||||
|
.social-card>img {
|
||||||
width: 4.7em;
|
width: 4.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.social-message {
|
.social-message {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
.join-scls, .footer-scls {
|
|
||||||
|
.join-scls,
|
||||||
|
.footer-scls {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
max-width: 55em;
|
max-width: 55em;
|
||||||
|
@ -231,6 +273,7 @@ a:hover {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-left: 5em;
|
margin-left: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carousel-item {
|
.carousel-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -240,45 +283,58 @@ a:hover {
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
}
|
}
|
||||||
.carousel-item > img {
|
|
||||||
|
.carousel-item>img {
|
||||||
width: 18.7em;
|
width: 18.7em;
|
||||||
|
border-radius: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carousel-name {
|
.carousel-name {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carousel-pos {
|
.carousel-pos {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carousel-email {
|
.carousel-email {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carousel-page {
|
.carousel-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carousel {
|
.carousel {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carousel-left {
|
.carousel-left {
|
||||||
margin-left: 2em;
|
margin-left: 2em;
|
||||||
transform: scaleX(-1);
|
transform: scaleX(-1);
|
||||||
}
|
}
|
||||||
.carousel-right, .carousel-left {
|
|
||||||
|
.carousel-right,
|
||||||
|
.carousel-left {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 4em;
|
width: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.carousel-right {
|
.carousel-right {
|
||||||
margin-right: 2em;
|
margin-right: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact {
|
.contact {
|
||||||
border-radius: 0 0 50% 50% / 4rem;
|
border-radius: 0 0 50% 50% / 4rem;
|
||||||
transform: translateY(4rem);
|
transform: translateY(4rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
background-color: var(--main);
|
background-color: var(--main);
|
||||||
padding-top: 7em;
|
padding-top: 7em;
|
||||||
|
@ -288,18 +344,22 @@ a:hover {
|
||||||
padding-left: 2em;
|
padding-left: 2em;
|
||||||
padding-right: 2em;
|
padding-right: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer a {
|
.footer a {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-scls {
|
.footer-scls {
|
||||||
max-width: 30em;
|
max-width: 30em;
|
||||||
font-size: 0.6em;
|
font-size: 0.6em;
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-scls img {
|
.footer-scls img {
|
||||||
width: 4.7em;
|
width: 4.7em;
|
||||||
}
|
}
|
||||||
.footer > img {
|
|
||||||
|
.footer>img {
|
||||||
width: 30em;
|
width: 30em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,27 +369,33 @@ a:hover {
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 650px) {
|
@media screen and (max-width: 650px) {
|
||||||
html {
|
html {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
.footer > img{
|
|
||||||
|
.footer>img {
|
||||||
width: 15em;
|
width: 15em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 540px) {
|
@media screen and (max-width: 540px) {
|
||||||
html {
|
html {
|
||||||
font-size: 0.6em;
|
font-size: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer>img {
|
.footer>img {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 420px) {
|
@media screen and (max-width: 420px) {
|
||||||
html {
|
html {
|
||||||
font-size: 0.5em;
|
font-size: 0.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 320px) {
|
@media screen and (max-width: 320px) {
|
||||||
html {
|
html {
|
||||||
font-size: 0.45em;
|
font-size: 0.45em;
|
||||||
|
@ -337,7 +403,7 @@ a:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
#cal {
|
#cal {
|
||||||
border:solid 1px #777;
|
border: solid 1px #777;
|
||||||
width: 800px;
|
width: 800px;
|
||||||
height: 600px;
|
height: 600px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as ReactDom from "react-dom";
|
import * as ReactDom from "react-dom";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import TopBar from "./components/TopBar";
|
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 Splash from "./components/Splash";
|
||||||
import DefaultSection from "./components/DefaultSection";
|
import DefaultSection from "./components/DefaultSection";
|
||||||
import InvolveBox from "./components/InvolveBox";
|
import InvolveBox from "./components/InvolveBox";
|
||||||
|
@ -18,30 +18,51 @@ class Main extends React.Component<MainProps, MainState> {
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return <>
|
return (
|
||||||
|
<>
|
||||||
<TopBar links={ACTIVE_PAGES}></TopBar>
|
<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">
|
<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>
|
||||||
|
|
||||||
<DefaultSection title="Open Access Hours">
|
<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>
|
</DefaultSection>
|
||||||
|
|
||||||
<div id="contact-us">
|
<div id="contact-us">
|
||||||
<DefaultSection className="contact" title="Have questions? Contact us!">
|
<DefaultSection
|
||||||
<div className="join-scls">{
|
className="contact"
|
||||||
[...EMAIL, ...SOCIALS].map(n => (
|
title="Have questions? Contact us!"
|
||||||
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
|
>
|
||||||
))
|
<div className="join-scls">
|
||||||
}</div>
|
{[...EMAIL, ...SOCIALS].map((n) => (
|
||||||
|
<SocialCard
|
||||||
|
url={n.url}
|
||||||
|
image={n.icon}
|
||||||
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</DefaultSection>
|
</DefaultSection>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</>;
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 147 KiB |
BIN
src/public/img/backgrounds/committee.webp
Normal file
After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 915 KiB |
BIN
src/public/img/backgrounds/fa21qp.webp
Normal file
After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 449 KiB |
BIN
src/public/img/backgrounds/fa21social.webp
Normal file
After Width: | Height: | Size: 275 KiB |
Before Width: | Height: | Size: 184 KiB |
BIN
src/public/img/backgrounds/gbm.webp
Normal file
After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 11 MiB |
BIN
src/public/img/backgrounds/micromouse.webp
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 771 KiB |
BIN
src/public/img/backgrounds/ps.webp
Normal file
After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 2 MiB |
BIN
src/public/img/backgrounds/robocar.webp
Normal file
After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 24 MiB |
Before Width: | Height: | Size: 250 KiB |
BIN
src/public/img/backgrounds/robofest.webp
Normal file
After Width: | Height: | Size: 121 KiB |
Before Width: | Height: | Size: 16 MiB |
BIN
src/public/img/backgrounds/sp22qp.webp
Normal file
After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 896 KiB |
BIN
src/public/img/committees/outreach.webp
Normal file
After Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 897 KiB |
BIN
src/public/img/committees/pr.webp
Normal file
After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 167 KiB |
BIN
src/public/img/committees/professional.webp
Normal file
After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 480 KiB |
BIN
src/public/img/committees/social.webp
Normal file
After Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 356 KiB |
BIN
src/public/img/committees/technical.webp
Normal file
After Width: | Height: | Size: 62 KiB |
|
@ -1,7 +1,7 @@
|
||||||
import * as ReactDom from "react-dom";
|
import * as ReactDom from "react-dom";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import TopBar from "./components/TopBar";
|
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 Splash from "./components/Splash";
|
||||||
import DefaultSection from "./components/DefaultSection";
|
import DefaultSection from "./components/DefaultSection";
|
||||||
import InvolveBox from "./components/InvolveBox";
|
import InvolveBox from "./components/InvolveBox";
|
||||||
|
@ -18,42 +18,89 @@ class Main extends React.Component<MainProps, MainState> {
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return <>
|
return (
|
||||||
|
<>
|
||||||
<TopBar links={ACTIVE_PAGES}></TopBar>
|
<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">
|
<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!",
|
"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 world’s largest professional organization. On the student level, we provide members with a plethora of ways to get involved!"
|
"The Institute of Electrical and Electronics Engineers (IEEE) UC San Diego student branch is the second largest student chapter in the world’s largest professional organization. On the student level, we provide members with a plethora of ways to get involved!",
|
||||||
]}></DefaultSection>
|
]}
|
||||||
|
></DefaultSection>
|
||||||
</div>
|
</div>
|
||||||
<div className="project-space">
|
<div className="project-space">
|
||||||
<div className="ps-title">Join us at the Project Space!</div>
|
<div className="ps-title">
|
||||||
<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>
|
Join us at the Project Space!
|
||||||
<a className="visit-us" href="https://www.google.com/maps/@32.8817126,-117.2350998,59m/">Come visit at EBU1-4710!</a>
|
|
||||||
</div>
|
</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">
|
<div className="cards">
|
||||||
<InvolveBox boxTitle="Events" image="img/backgrounds/fa21social.png" description="Meet fellow IEEE members!"></InvolveBox>
|
<InvolveBox
|
||||||
<InvolveBox boxTitle="Projects" image="img/backgrounds/robofest.png" description="Learn new skills!"></InvolveBox>
|
boxTitle="Events"
|
||||||
<InvolveBox boxTitle="Committees" image="img/backgrounds/gbm.png" description="Build our amazing community!"></InvolveBox>
|
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>
|
</div>
|
||||||
</DefaultSection>
|
</DefaultSection>
|
||||||
|
|
||||||
<div id="contact-us">
|
<div id="contact-us">
|
||||||
<DefaultSection title="Have questions? Contact us!">
|
<DefaultSection title="Have questions? Contact us!">
|
||||||
<div className="join-scls">{
|
<div className="join-scls">
|
||||||
[...EMAIL, ...SOCIALS].map(n => (
|
{[...EMAIL, ...SOCIALS].map((n) => (
|
||||||
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
|
<SocialCard
|
||||||
))
|
url={n.url}
|
||||||
}</div>
|
image={n.icon}
|
||||||
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</DefaultSection>
|
</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>
|
<Carousel items={OFFICERS} itemsPerPage={6}></Carousel>
|
||||||
</DefaultSection>
|
</DefaultSection>
|
||||||
</div>
|
</div>
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</>;
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as ReactDom from "react-dom";
|
import * as ReactDom from "react-dom";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import TopBar from "./components/TopBar";
|
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 Splash from "./components/Splash";
|
||||||
import DefaultSection from "./components/DefaultSection";
|
import DefaultSection from "./components/DefaultSection";
|
||||||
import InvolveBox from "./components/InvolveBox";
|
import InvolveBox from "./components/InvolveBox";
|
||||||
|
@ -18,40 +18,78 @@ class Main extends React.Component<MainProps, MainState> {
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return <>
|
return (
|
||||||
|
<>
|
||||||
<TopBar links={ACTIVE_PAGES}></TopBar>
|
<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>
|
<Splash
|
||||||
<DefaultSection title="RoboCup" paragraphs={[
|
cta="Gain hands-on experience to make your resume stand out! No experience required!"
|
||||||
"\"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.\""
|
delay={2000}
|
||||||
,"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!"
|
backgrounds={["img/backgrounds/robocar.webp"]}
|
||||||
]}>
|
></Splash>
|
||||||
<a className='ex-link' href='https://www.robocup.org/'>RoboCup website</a>
|
<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>
|
||||||
<DefaultSection title="Quarterly Projects" paragraphs={[
|
<DefaultSection
|
||||||
"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."
|
title="Quarterly Projects"
|
||||||
]}>
|
paragraphs={[
|
||||||
<a className='ex-link' href='https://forms.gle/eW6e1i3vWCdBj7Vn6'>Apply here</a>
|
"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>
|
||||||
<DefaultSection className={"past-proj"} title="Past Projects">
|
<DefaultSection className={"past-proj"} title="Past Projects">
|
||||||
<div className="cards">
|
<div className="cards">
|
||||||
<InvolveBox boxTitle="" image="img/backgrounds/robocar.png" description="'22 Robocar Competition"></InvolveBox>
|
<InvolveBox
|
||||||
<InvolveBox boxTitle="" image="img/backgrounds/micromouse.png" description="'22 Micromouse Competition"></InvolveBox>
|
boxTitle=""
|
||||||
<InvolveBox boxTitle="" image="img/backgrounds/sp22qp.png" description="'22 Spring QP Showcase"></InvolveBox>
|
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>
|
</div>
|
||||||
</DefaultSection>
|
</DefaultSection>
|
||||||
|
|
||||||
<div id="contact-us">
|
<div id="contact-us">
|
||||||
<DefaultSection className="contact" title="Have questions? Contact us!">
|
<DefaultSection
|
||||||
<div className="join-scls">{
|
className="contact"
|
||||||
[...EMAIL, ...SOCIALS].map(n => (
|
title="Have questions? Contact us!"
|
||||||
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
|
>
|
||||||
))
|
<div className="join-scls">
|
||||||
}</div>
|
{[...EMAIL, ...SOCIALS].map((n) => (
|
||||||
|
<SocialCard
|
||||||
|
url={n.url}
|
||||||
|
image={n.icon}
|
||||||
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</DefaultSection>
|
</DefaultSection>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</>;
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>$TITLE</title>
|
<title>$TITLE</title>
|
||||||
<link rel="stylesheet" type="text/css" href="css/fonts.css" media="screen">
|
<link rel="stylesheet" type="text/css" href="css/fonts.css" media="screen">
|
||||||
|
@ -9,8 +10,10 @@
|
||||||
<meta name="description" content="$DESCRIPTION">
|
<meta name="description" content="$DESCRIPTION">
|
||||||
<meta name="theme-color" content="$THEMECOLOR">
|
<meta name="theme-color" content="$THEMECOLOR">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="text/javascript" src="$JSFILE"></script>
|
<script type="text/javascript" src="$JSFILE"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,29 +1,30 @@
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const CopyPlugin = require("copy-webpack-plugin");
|
const CopyPlugin = require("copy-webpack-plugin");
|
||||||
const LicensePlugin = require("license-webpack-plugin").LicenseWebpackPlugin;
|
const LicensePlugin = require("license-webpack-plugin").LicenseWebpackPlugin;
|
||||||
const TerserPlugin = require('terser-webpack-plugin');
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: loadEntries("./src/public"),
|
entry: loadEntries("./src/public"),
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, "build/public"),
|
path: path.resolve(__dirname, "build/public"),
|
||||||
filename: "./js/[name].js"
|
filename: "./js/[name].js",
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [{
|
rules: [
|
||||||
|
{
|
||||||
test: /\.(tsx|ts)$/,
|
test: /\.(tsx|ts)$/,
|
||||||
use: "ts-loader"
|
use: "ts-loader",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(js)$/,
|
test: /\.(js)$/,
|
||||||
use: "babel-loader"
|
use: "babel-loader",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: ["style-loader", "css-loader"]
|
use: ["style-loader", "css-loader"],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".tsx", ".ts", ".js"],
|
extensions: [".tsx", ".ts", ".js"],
|
||||||
|
@ -31,18 +32,19 @@ module.exports = {
|
||||||
mode: "production",
|
mode: "production",
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyPlugin({
|
new CopyPlugin({
|
||||||
patterns: [{
|
patterns: [
|
||||||
|
{
|
||||||
from: "./src/public",
|
from: "./src/public",
|
||||||
to: ".",
|
to: ".",
|
||||||
globOptions: {
|
globOptions: {
|
||||||
ignore: ["**/*.tsx", "**/*.ts"]
|
ignore: ["**/*.tsx", "**/*.ts"],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
new LicensePlugin({
|
new LicensePlugin({
|
||||||
outputFilename: 'third-party-notice.txt'
|
outputFilename: "third-party-notice.txt",
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: true,
|
minimize: true,
|
||||||
|
@ -58,12 +60,15 @@ module.exports = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
//devtool: "source-map"
|
//devtool: "source-map"
|
||||||
|
devServer: {
|
||||||
|
static: "./build/public",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadEntries(dir) {
|
function loadEntries(dir) {
|
||||||
let files = fs.readdirSync(path.join(__dirname, dir));
|
let files = fs.readdirSync(path.join(__dirname, dir));
|
||||||
let entries = {};
|
let entries = {};
|
||||||
files.forEach(file => {
|
files.forEach((file) => {
|
||||||
let name = file.match(/^(.*)\.tsx$/);
|
let name = file.match(/^(.*)\.tsx$/);
|
||||||
if (name) {
|
if (name) {
|
||||||
entries[name[1]] = path.join(__dirname, dir, file);
|
entries[name[1]] = path.join(__dirname, dir, file);
|
||||||
|
|