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%
2
.gitignore
vendored
|
@ -1,3 +1,3 @@
|
||||||
build
|
build
|
||||||
dist
|
dist
|
||||||
node_modules
|
node_modules
|
||||||
|
|
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
17
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,15 +35,22 @@
|
||||||
"@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"
|
||||||
}
|
}
|
||||||
}
|
}
|
400
src/Database.ts
|
@ -1,208 +1,236 @@
|
||||||
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(
|
||||||
display: String,
|
"User",
|
||||||
email: {
|
new Schema({
|
||||||
public: Boolean,
|
display: String,
|
||||||
text: String,
|
email: {
|
||||||
},
|
public: Boolean,
|
||||||
picture: String,
|
text: String,
|
||||||
password: {
|
},
|
||||||
hash: Buffer,
|
picture: String,
|
||||||
salt: Buffer
|
password: {
|
||||||
},
|
hash: Buffer,
|
||||||
bio: {type: String, default: ""},
|
salt: Buffer,
|
||||||
isOfficer: {type: Boolean, default: false},
|
},
|
||||||
title: {type: String, default: "Member"},
|
bio: { type: String, default: "" },
|
||||||
uuid: String
|
isOfficer: { type: Boolean, default: false },
|
||||||
}));
|
title: { type: String, default: "Member" },
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
interface HashSalt {
|
interface HashSalt {
|
||||||
hash: Buffer;
|
hash: Buffer;
|
||||||
salt: Buffer;
|
salt: Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class UserDatabase {
|
export default class UserDatabase {
|
||||||
|
// How many iterations pbkdf2 will iterate the password hashing algorithm
|
||||||
|
private static PW_ITERATIONS = 100000;
|
||||||
|
// The length of the salt that should be used with every password hash
|
||||||
|
private static SALT_LENGTH = 64;
|
||||||
|
// How many bytes will be used to generate a UUID of length 2 times this variable
|
||||||
|
private static UUID_LENGTH = 32;
|
||||||
|
|
||||||
// How many iterations pbkdf2 will iterate the password hashing algorithm
|
/**
|
||||||
private static PW_ITERATIONS = 100000;
|
* Makes a new UserDatabase
|
||||||
// The length of the salt that should be used with every password hash
|
* @param url the mongodb database url to connect to
|
||||||
private static SALT_LENGTH = 64;
|
*/
|
||||||
// How many bytes will be used to generate a UUID of length 2 times this variable
|
constructor(url: string) {
|
||||||
private static UUID_LENGTH = 32;
|
mongoose.connect(url);
|
||||||
|
mongoose.set("returnOriginal", false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// Functions to edit current users
|
||||||
* Makes a new UserDatabase
|
/**
|
||||||
* @param url the mongodb database url to connect to
|
* Changes a user's display name on the website
|
||||||
*/
|
* @param uuid the UUID of the user
|
||||||
constructor(url: string) {
|
* @param newName the user's new name
|
||||||
mongoose.connect(url);
|
*/
|
||||||
mongoose.set("returnOriginal", false);
|
public async setName(uuid: string, newName: string) {
|
||||||
}
|
await User.findOneAndUpdate({ uuid: uuid }, { name: newName }).exec();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Gets the display name of a user with a given UUID
|
||||||
|
* @param uuid the UUID of the user
|
||||||
|
* @returns the user's display name
|
||||||
|
*/
|
||||||
|
public async getName(uuid: string): Promise<string> {
|
||||||
|
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
|
||||||
|
.display;
|
||||||
|
}
|
||||||
|
|
||||||
// Functions to edit current users
|
/**
|
||||||
/**
|
* Updates a user's display email
|
||||||
* Changes a user's display name on the website
|
* @param uuid the UUID of the user
|
||||||
* @param uuid the UUID of the user
|
* @param newEmail the user's new display email
|
||||||
* @param newName the user's new name
|
*/
|
||||||
*/
|
public async setEmail(uuid: string, newEmail: string) {
|
||||||
public async setName(uuid: string, newName: string) {
|
await User.findOneAndUpdate({ uuid: uuid }, { email: newEmail }).exec();
|
||||||
await User.findOneAndUpdate({uuid: uuid}, {name: newName}).exec();
|
}
|
||||||
}
|
/**
|
||||||
/**
|
* Gets the email of a user with a given UUID
|
||||||
* Gets the display name of a user with a given UUID
|
* @param uuid the UUID of the user
|
||||||
* @param uuid the UUID of the user
|
* @returns the user's email
|
||||||
* @returns the user's display name
|
*/
|
||||||
*/
|
public async getEmail(uuid: string): Promise<string> {
|
||||||
public async getName(uuid: string): Promise<string> {
|
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
|
||||||
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).display;
|
.email;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a user's display email
|
* Updates a user's password
|
||||||
* @param uuid the UUID of the user
|
* @param uuid the UUID of the user
|
||||||
* @param newEmail the user's new display email
|
* @param newPassword the user's new password
|
||||||
*/
|
*/
|
||||||
public async setEmail(uuid: string, newEmail: string) {
|
public async setPassword(uuid: string, newPassword: string) {
|
||||||
await User.findOneAndUpdate({uuid: uuid}, {email: newEmail}).exec();
|
let hashsalt = await UserDatabase.hash(newPassword);
|
||||||
}
|
await User.findOneAndUpdate(
|
||||||
/**
|
{ uuid: uuid },
|
||||||
* Gets the email of a user with a given UUID
|
{ password: hashsalt }
|
||||||
* @param uuid the UUID of the user
|
).exec();
|
||||||
* @returns the user's email
|
}
|
||||||
*/
|
/**
|
||||||
public async getEmail(uuid: string): Promise<string> {
|
* Gets the password of a user with a given UUID
|
||||||
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).email;
|
* @param uuid the UUID of the user
|
||||||
}
|
* @returns the user's password
|
||||||
|
*/
|
||||||
|
public async getPasswordHash(uuid: string): Promise<Buffer> {
|
||||||
|
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
|
||||||
|
.password.hash;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a user's password
|
* Updates a member's position
|
||||||
* @param uuid the UUID of the user
|
* @param uuid the UUID of the user
|
||||||
* @param newPassword the user's new password
|
* @param newTitle the user's new officer title/position
|
||||||
*/
|
*/
|
||||||
public async setPassword(uuid: string, newPassword: string) {
|
public async setRank(uuid: string, newTitle: string, isOfficer: boolean) {
|
||||||
let hashsalt = await UserDatabase.hash(newPassword);
|
await User.findOneAndUpdate(
|
||||||
await User.findOneAndUpdate({uuid: uuid}, {password: hashsalt}).exec();
|
{ uuid: uuid },
|
||||||
}
|
{ title: newTitle, isOfficer: isOfficer }
|
||||||
/**
|
).exec();
|
||||||
* Gets the password of a user with a given UUID
|
}
|
||||||
* @param uuid the UUID of the user
|
/**
|
||||||
* @returns the user's password
|
* Gets the title of a user with a given UUID
|
||||||
*/
|
* @param uuid the UUID of the user
|
||||||
public async getPasswordHash(uuid: string): Promise<Buffer> {
|
* @returns the user's title
|
||||||
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).password.hash;
|
*/
|
||||||
}
|
public async getRank(uuid: string): Promise<string> {
|
||||||
|
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
|
||||||
|
.title;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Gets whether of a user with a given UUID is an officer
|
||||||
|
* @param uuid the UUID of the user
|
||||||
|
* @returns true if the user is an officer
|
||||||
|
*/
|
||||||
|
public async isOfficer(uuid: string): Promise<boolean> {
|
||||||
|
return ((await User.findOne({ uuid: uuid }).lean().exec()) as DBUser)
|
||||||
|
.isOfficer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a member's position
|
* Sets the user's new profile picture
|
||||||
* @param uuid the UUID of the user
|
* @param uuid the UUID of the user
|
||||||
* @param newTitle the user's new officer title/position
|
* @param newPic the link to the new URL of the profile picture
|
||||||
*/
|
*/
|
||||||
public async setRank(uuid: string, newTitle: string, isOfficer: boolean) {
|
public async setPicture(uuid: string, newPic: string) {
|
||||||
await User.findOneAndUpdate({uuid: uuid}, {title: newTitle, isOfficer: isOfficer}).exec();
|
await User.findOneAndUpdate({ uuid: uuid }, { picture: newPic }).exec();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Gets the title of a user with a given UUID
|
* Gets the profile picture of a user with a given UUID
|
||||||
* @param uuid the UUID of the user
|
* @param uuid the UUID of the user
|
||||||
* @returns the user's title
|
* @returns the user's profile picture
|
||||||
*/
|
*/
|
||||||
public async getRank(uuid: string): Promise<string> {
|
public async getPicture(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)
|
||||||
}
|
.picture;
|
||||||
/**
|
}
|
||||||
* Gets whether of a user with a given UUID is an officer
|
|
||||||
* @param uuid the UUID of the user
|
|
||||||
* @returns true if the user is an officer
|
|
||||||
*/
|
|
||||||
public async isOfficer(uuid: string): Promise<boolean> {
|
|
||||||
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).isOfficer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public async getUser(uuid: string): Promise<DBUser> {
|
||||||
* Sets the user's new profile picture
|
return User.findOne({ uuid: uuid }).exec() as Promise<DBUser>;
|
||||||
* @param uuid the UUID of the user
|
}
|
||||||
* @param newPic the link to the new URL of the profile picture
|
|
||||||
*/
|
|
||||||
public async setPicture(uuid: string, newPic: string) {
|
|
||||||
await User.findOneAndUpdate({uuid: uuid}, {picture: newPic}).exec();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Gets the profile picture of a user with a given UUID
|
|
||||||
* @param uuid the UUID of the user
|
|
||||||
* @returns the user's profile picture
|
|
||||||
*/
|
|
||||||
public async getPicture(uuid: string): Promise<string> {
|
|
||||||
return (await User.findOne({uuid: uuid}).lean().exec() as DBUser).picture;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getUser(uuid: string): Promise<DBUser> {
|
// User creation and deletion functions
|
||||||
return User.findOne({uuid: uuid}).exec() as Promise<DBUser>;
|
/**
|
||||||
}
|
* Deletes a user with the given UUID
|
||||||
|
* @param uuid the UUID of the user
|
||||||
|
*/
|
||||||
|
public async deleteUser(uuid: string) {
|
||||||
|
await User.findOneAndDelete({ uuid: uuid }).exec();
|
||||||
|
}
|
||||||
|
|
||||||
// User creation and deletion functions
|
/**
|
||||||
/**
|
* Makes a new user and adds it to the database
|
||||||
* Deletes a user with the given UUID
|
* @param display the user's display name
|
||||||
* @param uuid the UUID of the user
|
* @param email the user's display email
|
||||||
*/
|
* @param picture the user's picture
|
||||||
public async deleteUser(uuid: string) {
|
* @param password the user's plaintext password
|
||||||
await User.findOneAndDelete({uuid: uuid}).exec();
|
*/
|
||||||
}
|
public async makeNewUser(
|
||||||
|
display: string,
|
||||||
|
email: string,
|
||||||
|
picture: string,
|
||||||
|
password: string,
|
||||||
|
title?: string,
|
||||||
|
isOfficer?: boolean
|
||||||
|
): Promise<void> {
|
||||||
|
let encrypted = await UserDatabase.hash(password);
|
||||||
|
await new User({
|
||||||
|
display: display,
|
||||||
|
email: email,
|
||||||
|
picture: picture,
|
||||||
|
password: encrypted,
|
||||||
|
uuid: UserDatabase.genUUID(),
|
||||||
|
isOfficer: !!isOfficer,
|
||||||
|
title: title ? title : "Member",
|
||||||
|
}).save();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// Utility functions
|
||||||
* Makes a new user and adds it to the database
|
/**
|
||||||
* @param display the user's display name
|
* Hashes a password using a salt of 64 random bytes and pbkdf2 with 100000 iterations
|
||||||
* @param email the user's display email
|
* @param password the password as a string that should be hashed
|
||||||
* @param picture the user's picture
|
* @returns the hashed password
|
||||||
* @param password the user's plaintext password
|
*/
|
||||||
*/
|
public static async hash(password: string): Promise<HashSalt> {
|
||||||
public async makeNewUser(display: string, email: string, picture: string, password: string, title?: string, isOfficer?: boolean): Promise<void> {
|
let salt = randomBytes(UserDatabase.SALT_LENGTH);
|
||||||
let encrypted = await UserDatabase.hash(password);
|
let pass = Buffer.from(String.prototype.normalize(password));
|
||||||
await (new User({
|
return {
|
||||||
display: display,
|
hash: await pbkdf(
|
||||||
email: email,
|
pass,
|
||||||
picture: picture,
|
salt,
|
||||||
password: encrypted,
|
UserDatabase.PW_ITERATIONS,
|
||||||
uuid: UserDatabase.genUUID(),
|
512,
|
||||||
isOfficer: !!isOfficer,
|
"sha512"
|
||||||
title: title ? title : "Member"
|
),
|
||||||
})).save();
|
salt: salt,
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Utility functions
|
/**
|
||||||
/**
|
* Generates a UUID for a user or anything else
|
||||||
* Hashes a password using a salt of 64 random bytes and pbkdf2 with 100000 iterations
|
* @returns a random hex string of length 2 * UUID_LENGTH
|
||||||
* @param password the password as a string that should be hashed
|
*/
|
||||||
* @returns the hashed password
|
public static genUUID(): string {
|
||||||
*/
|
return Array.from(randomBytes(UserDatabase.UUID_LENGTH))
|
||||||
public static async hash(password: string): Promise<HashSalt> {
|
.map((val) => val.toString(16).padStart(2, "0"))
|
||||||
let salt = randomBytes(UserDatabase.SALT_LENGTH);
|
.join("");
|
||||||
let pass = Buffer.from(String.prototype.normalize(password));
|
}
|
||||||
return {
|
}
|
||||||
hash: await pbkdf(pass, salt, UserDatabase.PW_ITERATIONS, 512, "sha512"),
|
|
||||||
salt: salt
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a UUID for a user or anything else
|
|
||||||
* @returns a random hex string of length 2 * UUID_LENGTH
|
|
||||||
*/
|
|
||||||
public static genUUID(): string {
|
|
||||||
return Array.from(randomBytes(UserDatabase.UUID_LENGTH))
|
|
||||||
.map(val=>(val.toString(16).padStart(2,"0"))).join("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
174
src/index.ts
|
@ -1,121 +1,129 @@
|
||||||
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";
|
||||||
|
|
||||||
interface Website {
|
interface Website {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
sitename: string;
|
sitename: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
jsfile: string;
|
jsfile: string;
|
||||||
cssfile: string;
|
cssfile: string;
|
||||||
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"))
|
||||||
sitename: "index",
|
.toString();
|
||||||
title: "IEEE at UCSD",
|
const WEBSITES = [
|
||||||
description: "",
|
{
|
||||||
jsfile: "js/index.js",
|
sitename: "index",
|
||||||
cssfile: "css/styles.css",
|
title: "IEEE at UCSD",
|
||||||
themecolor: ""
|
description: "",
|
||||||
},
|
jsfile: "js/index.js",
|
||||||
{
|
cssfile: "css/styles.css",
|
||||||
sitename: "events",
|
themecolor: "",
|
||||||
title: "IEEE at UCSD",
|
},
|
||||||
description: "",
|
{
|
||||||
jsfile: "js/events.js",
|
sitename: "events",
|
||||||
cssfile: "css/styles.css",
|
title: "IEEE at UCSD",
|
||||||
themecolor: ""
|
description: "",
|
||||||
},
|
jsfile: "js/events.js",
|
||||||
{
|
cssfile: "css/styles.css",
|
||||||
sitename: "projects",
|
themecolor: "",
|
||||||
title: "IEEE at UCSD",
|
},
|
||||||
description: "",
|
{
|
||||||
jsfile: "js/projects.js",
|
sitename: "projects",
|
||||||
cssfile: "css/styles.css",
|
title: "IEEE at UCSD",
|
||||||
themecolor: ""
|
description: "",
|
||||||
},
|
jsfile: "js/projects.js",
|
||||||
{
|
cssfile: "css/styles.css",
|
||||||
sitename: "committees",
|
themecolor: "",
|
||||||
title: "IEEE at UCSD",
|
},
|
||||||
description: "",
|
{
|
||||||
jsfile: "js/committees.js",
|
sitename: "committees",
|
||||||
cssfile: "css/styles.css",
|
title: "IEEE at UCSD",
|
||||||
themecolor: ""
|
description: "",
|
||||||
},
|
jsfile: "js/committees.js",
|
||||||
{
|
cssfile: "css/styles.css",
|
||||||
sitename: "contact",
|
themecolor: "",
|
||||||
title: "IEEE at UCSD",
|
},
|
||||||
description: "",
|
{
|
||||||
jsfile: "js/index.js",
|
sitename: "contact",
|
||||||
cssfile: "css/styles.css",
|
title: "IEEE at UCSD",
|
||||||
themecolor: ""
|
description: "",
|
||||||
}
|
jsfile: "js/index.js",
|
||||||
|
cssfile: "css/styles.css",
|
||||||
|
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");
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility functions for above methods
|
* Utility functions for above methods
|
||||||
*/
|
*/
|
||||||
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]);
|
||||||
}
|
}
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
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",
|
{
|
||||||
url: "/"
|
name: "Home",
|
||||||
}, {
|
url: "/",
|
||||||
name: "Events",
|
},
|
||||||
url: "/events"
|
{
|
||||||
}, {
|
name: "Events",
|
||||||
name: "Projects",
|
url: "/events",
|
||||||
url: "/projects"
|
},
|
||||||
}, {
|
{
|
||||||
name: "Committees",
|
name: "Projects",
|
||||||
url: "/committees"
|
url: "/projects",
|
||||||
}, {
|
},
|
||||||
name: "Contact Us",
|
{
|
||||||
url: "/contact"
|
name: "Committees",
|
||||||
}];
|
url: "/committees",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Contact Us",
|
||||||
|
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 = [
|
||||||
|
{
|
||||||
|
icon: "img/disc.svg",
|
||||||
|
url: "https://discord.gg/XxfjqZSjca",
|
||||||
|
message: "Join our server",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "img/fab.svg",
|
||||||
|
url: "https://www.facebook.com/ieeeucsd",
|
||||||
|
message: "ieeeucsd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "img/inst.svg",
|
||||||
|
url: "https://www.instagram.com/ieee.ucsd",
|
||||||
|
message: "@ieeeucsd",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const EMAIL = [
|
||||||
|
{
|
||||||
|
icon: "img/email.svg",
|
||||||
|
url: "mailto:ieee@eng.ucsd.edu",
|
||||||
|
message: "ieee@eng.ucsd.edu",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const EMAIL_WHITE = [
|
||||||
|
{
|
||||||
|
icon: "img/email_white.svg",
|
||||||
|
url: "mailto:ieee@eng.ucsd.edu",
|
||||||
|
message: "ieee@eng.ucsd.edu",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const SOCIALS = [{
|
export const SOCIALS_WHITE = [
|
||||||
icon: "img/disc.svg",
|
{
|
||||||
url: "https://discord.gg/XxfjqZSjca",
|
icon: "img/disc_white.svg",
|
||||||
message: "Join our server"
|
url: "https://discord.gg/XxfjqZSjca",
|
||||||
}, {
|
message: "Join our server",
|
||||||
icon: "img/fab.svg",
|
},
|
||||||
url: "https://www.facebook.com/ieeeucsd",
|
{
|
||||||
message: "ieeeucsd"
|
icon: "img/fab_white.svg",
|
||||||
}, {
|
url: "https://www.facebook.com/ieeeucsd",
|
||||||
icon: "img/inst.svg",
|
message: "ieeeucsd",
|
||||||
url: "https://www.instagram.com/ieee.ucsd",
|
},
|
||||||
message: "@ieeeucsd"
|
{
|
||||||
}];
|
icon: "img/inst_white.svg",
|
||||||
export const EMAIL = [{
|
url: "https://www.instagram.com/ieee.ucsd",
|
||||||
icon: "img/email.svg",
|
message: "@ieeeucsd",
|
||||||
url: "mailto:ieee@eng.ucsd.edu",
|
},
|
||||||
message: "ieee@eng.ucsd.edu"
|
];
|
||||||
}];
|
|
||||||
export const EMAIL_WHITE = [{
|
|
||||||
icon: "img/email_white.svg",
|
|
||||||
url: "mailto:ieee@eng.ucsd.edu",
|
|
||||||
message: "ieee@eng.ucsd.edu"
|
|
||||||
}]
|
|
||||||
|
|
||||||
export const SOCIALS_WHITE = [{
|
export const OFFICERS = [
|
||||||
icon: "img/disc_white.svg",
|
{
|
||||||
url: "https://discord.gg/XxfjqZSjca",
|
name: "Darin Tsui",
|
||||||
message: "Join our server"
|
position: "Chair",
|
||||||
}, {
|
photo: "img/officers/darin.jpg",
|
||||||
icon: "img/fab_white.svg",
|
email: "email@ucsd.edu",
|
||||||
url: "https://www.facebook.com/ieeeucsd",
|
},
|
||||||
message: "ieeeucsd"
|
{
|
||||||
}, {
|
name: "Brigette Hacia",
|
||||||
icon: "img/inst_white.svg",
|
position: "Vice Chair Internal",
|
||||||
url: "https://www.instagram.com/ieee.ucsd",
|
photo: "img/officers/brigette.jpg",
|
||||||
message: "@ieeeucsd"
|
email: "email@ucsd.edu",
|
||||||
}];
|
},
|
||||||
export const OFFICERS = [{
|
{
|
||||||
name: "Darin Tsui",
|
name: "Tasnia Jamal",
|
||||||
position: "Chair",
|
position: "Vice Chair Events",
|
||||||
photo: "img/officers/darin.jpg",
|
photo: "img/officers/tasnia.jpg",
|
||||||
email: "email@ucsd.edu"
|
email: "email@ucsd.edu",
|
||||||
}, {
|
},
|
||||||
name: "Brigette Hacia",
|
{
|
||||||
position: "Vice Chair Internal",
|
name: "Kevin Chang",
|
||||||
photo: "img/officers/brigette.jpg",
|
position: "Vice Chair Projects",
|
||||||
email: "email@ucsd.edu"
|
photo: "img/officers/kevin.jpg",
|
||||||
}, {
|
email: "email@ucsd.edu",
|
||||||
name: "Tasnia Jamal",
|
},
|
||||||
position: "Vice Chair Events",
|
{
|
||||||
photo: "img/officers/tasnia.jpg",
|
name: "Arjun Sampath",
|
||||||
email: "email@ucsd.edu"
|
position: "Vice Chair Finance",
|
||||||
}, {
|
photo: "img/officers/arjun.jpg",
|
||||||
name: "Kevin Chang",
|
email: "email@ucsd.edu",
|
||||||
position: "Vice Chair Projects",
|
},
|
||||||
photo: "img/officers/kevin.jpg",
|
{
|
||||||
email: "email@ucsd.edu"
|
name: "Niklas Chang",
|
||||||
}, {
|
position: "Events Coordinator",
|
||||||
name: "Niklas Chang",
|
photo: "img/officers/niklas.jpg",
|
||||||
position: "Events Coordinator",
|
email: "email@ucsd.edu",
|
||||||
photo: "img/officers/niklas.jpg",
|
},
|
||||||
email: "email@ucsd.edu"
|
{
|
||||||
}, {
|
name: "Tien Vu",
|
||||||
name: "Tien Vu",
|
position: "Vice Chair External",
|
||||||
position: "Vice Chair External",
|
photo: "img/officers/tien.jpg",
|
||||||
photo: "img/officers/tien.jpg",
|
email: "email@ucsd.edu",
|
||||||
email: "email@ucsd.edu"
|
},
|
||||||
}, {
|
{
|
||||||
name: "Arjun Sampath",
|
name: "Derek Nguyen",
|
||||||
position: "Vice Chair Finance",
|
position: "Project Space Chair",
|
||||||
photo: "img/officers/arjun.jpg",
|
photo: "img/officers/derek.jpg",
|
||||||
email: "email@ucsd.edu"
|
email: "email@ucsd.edu",
|
||||||
}, {
|
},
|
||||||
name: "Derek Nguyen",
|
{
|
||||||
position: "Project Space Chair",
|
name: "Rafaella Gomes",
|
||||||
photo: "img/officers/derek.jpg",
|
position: "Robocup Chair",
|
||||||
email: "email@ucsd.edu"
|
photo: "img/officers/rafaella.jpg",
|
||||||
}, {
|
email: "email@ucsd.edu",
|
||||||
name: "Mohak Vaswani",
|
},
|
||||||
position: "Technical Chair",
|
{
|
||||||
photo: "img/officers/mohak.jpg",
|
name: "Yash Puneet",
|
||||||
email: "email@ucsd.edu"
|
position: "Robocup Chair",
|
||||||
}, {
|
photo: "img/officers/yash.jpg",
|
||||||
name: "Parisa Shahabi",
|
email: "email@ucsd.edu",
|
||||||
position: "Social Chair",
|
},
|
||||||
photo: "img/officers/parisa.jpg",
|
{
|
||||||
email: "email@ucsd.edu"
|
name: "Matthew Mikhailov",
|
||||||
}, {
|
position: "Supercomputing Chair",
|
||||||
name: "Vuong Bui",
|
photo: "img/officers/temp.png",
|
||||||
position: "Professional Chair",
|
email: "email@ucsd.edu",
|
||||||
photo: "img/officers/vuong.jpg",
|
},
|
||||||
email: "email@ucsd.edu"
|
{
|
||||||
}, {
|
name: "Josh Lapidario",
|
||||||
name: "Jason Liang",
|
position: "Quarterly Projects Chair",
|
||||||
position: "Professional Chair",
|
photo: "img/officers/josh.jpg",
|
||||||
photo: "img/officers/jason.jpg",
|
email: "email@ucsd.edu",
|
||||||
email: "email@ucsd.edu"
|
},
|
||||||
}, {
|
{
|
||||||
name: "Daniel Chen",
|
name: "Sanh Nguyen",
|
||||||
position: "Outreach Chair",
|
position: "Quarterly Projects Chair",
|
||||||
photo: "img/officers/daniel.jpg",
|
photo: "img/officers/temp.png",
|
||||||
email: "email@ucsd.edu"
|
email: "email@ucsd.edu",
|
||||||
}, {
|
},
|
||||||
name: "Dennis Liang",
|
{
|
||||||
position: "Outreach Chair",
|
name: "Vuong Bui",
|
||||||
photo: "img/officers/dennis.jpg",
|
position: "Professional Chair",
|
||||||
email: "email@ucsd.edu"
|
photo: "img/officers/vuong.jpg",
|
||||||
}, {
|
email: "email@ucsd.edu",
|
||||||
name: "Yash Puneet",
|
},
|
||||||
position: "Robocup Chair",
|
{
|
||||||
photo: "img/officers/yash.jpg",
|
name: "Jason Liang",
|
||||||
email: "email@ucsd.edu"
|
position: "Professional Chair",
|
||||||
}, {
|
photo: "img/officers/jason.jpg",
|
||||||
name: "Rafaella Gomes",
|
email: "email@ucsd.edu",
|
||||||
position: "Robocup Chair",
|
},
|
||||||
photo: "img/officers/rafaella.jpg",
|
{
|
||||||
email: "email@ucsd.edu"
|
name: "Mohak Vaswani",
|
||||||
}, {
|
position: "Technical Chair",
|
||||||
name: "Josh Lapidario",
|
photo: "img/officers/mohak.jpg",
|
||||||
position: "Quarterly Projects Chair",
|
email: "email@ucsd.edu",
|
||||||
photo: "img/officers/josh.jpg",
|
},
|
||||||
email: "email@ucsd.edu"
|
{
|
||||||
}, {
|
name: "Yusuf Morsi",
|
||||||
name: "Jiliana Tiu",
|
position: "Technical Chair",
|
||||||
position: "Webmaster",
|
photo: "img/officers/temp.png",
|
||||||
photo: "img/officers/jiliana.jpg",
|
email: "email@ucsd.edu",
|
||||||
email: "email@ucsd.edu"
|
},
|
||||||
}, {
|
{
|
||||||
name: "Stephanie Xu",
|
name: "Shaun Garcia",
|
||||||
position: "PR Chair - Graphics",
|
position: "Technical Chair",
|
||||||
photo: "img/officers/stephanie.jpg",
|
photo: "img/officers/temp.png",
|
||||||
email: "email@ucsd.edu"
|
email: "email@ucsd.edu",
|
||||||
}, {
|
},
|
||||||
name: "Sankalp Kaushik",
|
{
|
||||||
position: "PR Chair - Media",
|
name: "Dennis Liang",
|
||||||
photo: "img/officers/sankalp.jpg",
|
position: "Outreach Chair",
|
||||||
email: "email@ucsd.edu"
|
photo: "img/officers/dennis.jpg",
|
||||||
}, {
|
email: "email@ucsd.edu",
|
||||||
name: "Matthew Mikhailov",
|
},
|
||||||
position: "Supercomputing Chair",
|
{
|
||||||
photo: "img/officers/temp.png",
|
name: "Daniel Chen",
|
||||||
email: "email@ucsd.edu"
|
position: "Outreach Chair",
|
||||||
}, {
|
photo: "img/officers/daniel.jpg",
|
||||||
name: "Raymond Wang",
|
email: "email@ucsd.edu",
|
||||||
position: "Webmaster",
|
},
|
||||||
photo: "img/officers/temp.png",
|
{
|
||||||
email: "raymond@ucsd.edu"
|
name: "Parisa Shahabi",
|
||||||
}];
|
position: "Social Chair",
|
||||||
|
photo: "img/officers/parisa.jpg",
|
||||||
|
email: "email@ucsd.edu",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Matthew Yik",
|
||||||
|
position: "Social Chair",
|
||||||
|
photo: "img/officers/temp.png",
|
||||||
|
email: "email@ucsd.edu",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Jiliana Tiu",
|
||||||
|
position: "Webmaster",
|
||||||
|
photo: "img/officers/jiliana.jpg",
|
||||||
|
email: "email@ucsd.edu",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Raymond Wang",
|
||||||
|
position: "Webmaster",
|
||||||
|
photo: "img/officers/temp.png",
|
||||||
|
email: "raymond@ucsd.edu",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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";
|
||||||
|
@ -13,46 +13,81 @@ interface MainProps {}
|
||||||
interface MainState {}
|
interface MainState {}
|
||||||
|
|
||||||
class Main extends React.Component<MainProps, MainState> {
|
class Main extends React.Component<MainProps, MainState> {
|
||||||
constructor(props: MainProps) {
|
constructor(props: MainProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return <>
|
return (
|
||||||
<TopBar links={ACTIVE_PAGES}></TopBar>
|
<>
|
||||||
<Splash cta="The backbone of IEEE. Come help make a difference!" delay={2000} backgrounds={["img/backgrounds/committee.png"]}></Splash>
|
<TopBar links={ACTIVE_PAGES}></TopBar>
|
||||||
<DefaultSection title="Join us!" paragraphs={[
|
<Splash
|
||||||
"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!"
|
cta="The backbone of IEEE. Come help make a difference!"
|
||||||
]}>
|
delay={2000}
|
||||||
</DefaultSection>
|
backgrounds={["img/backgrounds/committee.webp"]}
|
||||||
<DefaultSection className={"our-comms"} title="Our Committees">
|
></Splash>
|
||||||
<div className="cards">
|
<DefaultSection
|
||||||
<InvolveBox boxTitle="" image="img/committees/technical.jpg" description="Technical Committee"></InvolveBox>
|
title="Join us!"
|
||||||
<InvolveBox boxTitle="" image="img/committees/social.jpg" description="Social Committee"></InvolveBox>
|
paragraphs={[
|
||||||
<InvolveBox boxTitle="" image="img/committees/professional.jpg" description="Professional Committee"></InvolveBox>
|
"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!",
|
||||||
<InvolveBox boxTitle="" image="img/committees/pr.jpg" description="PR Committee"></InvolveBox>
|
]}
|
||||||
<InvolveBox boxTitle="" image="img/committees/outreach.jpg" description="Outreach Committee"></InvolveBox>
|
></DefaultSection>
|
||||||
</div>
|
<DefaultSection className={"our-comms"} title="Our Committees">
|
||||||
</DefaultSection>
|
<div className="cards">
|
||||||
|
<InvolveBox
|
||||||
<div id="contact-us">
|
boxTitle=""
|
||||||
<DefaultSection title="Interested? Join our socials!">
|
image="img/committees/technical.webp"
|
||||||
<div className="join-scls">{
|
description="Technical Committee"
|
||||||
[...EMAIL, ...SOCIALS].map(n => (
|
></InvolveBox>
|
||||||
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
|
<InvolveBox
|
||||||
))
|
boxTitle=""
|
||||||
}</div>
|
image="img/committees/social.webp"
|
||||||
</DefaultSection>
|
description="Social Committee"
|
||||||
<DefaultSection className="contact" title="Or... Contact one of our staff!">
|
></InvolveBox>
|
||||||
<Carousel items={OFFICERS} itemsPerPage={6}></Carousel>
|
<InvolveBox
|
||||||
</DefaultSection>
|
boxTitle=""
|
||||||
</div>
|
image="img/committees/professional.webp"
|
||||||
|
description="Professional Committee"
|
||||||
|
></InvolveBox>
|
||||||
|
<InvolveBox
|
||||||
|
boxTitle=""
|
||||||
|
image="img/committees/pr.webp"
|
||||||
|
description="PR Committee"
|
||||||
|
></InvolveBox>
|
||||||
|
<InvolveBox
|
||||||
|
boxTitle=""
|
||||||
|
image="img/committees/outreach.webp"
|
||||||
|
description="Outreach Committee"
|
||||||
|
></InvolveBox>
|
||||||
|
</div>
|
||||||
|
</DefaultSection>
|
||||||
|
|
||||||
<Footer></Footer>
|
<div id="contact-us">
|
||||||
</>;
|
<DefaultSection title="Interested? Join our socials!">
|
||||||
}
|
<div className="join-scls">
|
||||||
|
{[...EMAIL, ...SOCIALS].map((n) => (
|
||||||
|
<SocialCard
|
||||||
|
url={n.url}
|
||||||
|
image={n.icon}
|
||||||
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</DefaultSection>
|
||||||
|
<DefaultSection
|
||||||
|
className="contact"
|
||||||
|
title="Or... Contact one of our staff!"
|
||||||
|
>
|
||||||
|
<Carousel items={OFFICERS} itemsPerPage={6}></Carousel>
|
||||||
|
</DefaultSection>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Footer></Footer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDom.render(<Main></Main>, document.getElementById("root"));
|
ReactDom.render(<Main></Main>, document.getElementById("root"));
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
|
|
@ -1,57 +1,81 @@
|
||||||
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";
|
||||||
|
|
||||||
interface CarouselProps {
|
interface CarouselProps {
|
||||||
items: CarouselItemProps[];
|
items: CarouselItemProps[];
|
||||||
itemsPerPage: number;
|
itemsPerPage: number;
|
||||||
}
|
}
|
||||||
interface CarouselState {
|
interface CarouselState {
|
||||||
page: number;
|
page: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Carousel extends Component<CarouselProps, CarouselState> {
|
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,25 +1,30 @@
|
||||||
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;
|
||||||
position: string;
|
position: string;
|
||||||
email: string;
|
email: string;
|
||||||
photo: string;
|
photo: string;
|
||||||
}
|
}
|
||||||
interface CarouselItemState {}
|
interface CarouselItemState {}
|
||||||
|
|
||||||
export default class CarouselItem extends Component<CarouselItemProps, CarouselItemState> {
|
export default class CarouselItem extends Component<
|
||||||
constructor(props: CarouselItemProps) {
|
CarouselItemProps,
|
||||||
super(props);
|
CarouselItemState
|
||||||
this.state = {};
|
> {
|
||||||
}
|
constructor(props: CarouselItemProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {};
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className="carousel-item">
|
return (
|
||||||
<img src={this.props.photo}></img>
|
<div className="carousel-item">
|
||||||
<div className="carousel-name">{this.props.name}</div>
|
<img src={this.props.photo}></img>
|
||||||
<div className="carousel-pos">{this.props.position}</div>
|
<div className="carousel-name">{this.props.name}</div>
|
||||||
</div>;
|
<div className="carousel-pos">{this.props.position}</div>
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,32 @@
|
||||||
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 {
|
||||||
items: CarouselItemProps[];
|
items: CarouselItemProps[];
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
interface CarouselPageState {}
|
interface CarouselPageState {}
|
||||||
|
|
||||||
export default class CarouselPage extends Component<CarouselPageProps, CarouselPageState> {
|
export default class CarouselPage extends Component<
|
||||||
constructor(props: CarouselPageProps) {
|
CarouselPageProps,
|
||||||
super(props);
|
CarouselPageState
|
||||||
this.state = {};
|
> {
|
||||||
}
|
constructor(props: CarouselPageProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {};
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className="carousel-page" style={this.props.visible ? {} : {display: "none"}}>{
|
return (
|
||||||
this.props.items.map(n=>(
|
<div
|
||||||
<CarouselItem {...n}></CarouselItem>
|
className="carousel-page"
|
||||||
))
|
style={this.props.visible ? {} : { display: "none" }}
|
||||||
}</div>;
|
>
|
||||||
}
|
{this.props.items.map((n) => (
|
||||||
|
<CarouselItem {...n}></CarouselItem>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,37 @@
|
||||||
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;
|
||||||
paragraphs?: string[];
|
paragraphs?: string[];
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
interface DefaultSectionState {}
|
interface DefaultSectionState {}
|
||||||
|
|
||||||
export default class DefaultSection extends Component<DefaultSectionProps, DefaultSectionState> {
|
export default class DefaultSection extends Component<
|
||||||
constructor(props: DefaultSectionProps) {
|
DefaultSectionProps,
|
||||||
super(props);
|
DefaultSectionState
|
||||||
this.state = {};
|
> {
|
||||||
}
|
constructor(props: DefaultSectionProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {};
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className={`default-section ${this.props.className ? this.props.className : ""}`}>
|
return (
|
||||||
<div className="section-title">{this.props.title}</div>
|
<div
|
||||||
{(this.props.paragraphs ? this.props.paragraphs : []).map(n=>(
|
className={`default-section ${
|
||||||
<p>{n}</p>
|
this.props.className ? this.props.className : ""
|
||||||
))}
|
}`}
|
||||||
{this.props.children}
|
>
|
||||||
</div>;
|
<div className="section-title">{this.props.title}</div>
|
||||||
}
|
{(this.props.paragraphs ? this.props.paragraphs : []).map(
|
||||||
|
(n) => (
|
||||||
|
<p>{n}</p>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,31 @@
|
||||||
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 {}
|
||||||
|
|
||||||
export default class Footer extends Component<FooterProps, FooterState> {
|
export default class Footer extends Component<FooterProps, FooterState> {
|
||||||
constructor(props: FooterProps) {
|
constructor(props: FooterProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className="footer">
|
return (
|
||||||
<img src="img/logo_white.svg"></img>
|
<div className="footer">
|
||||||
<div className="footer-scls">{
|
<img src="img/logo_white.svg"></img>
|
||||||
[...EMAIL_WHITE, ...SOCIALS_WHITE].map(n => (
|
<div className="footer-scls">
|
||||||
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
|
{[...EMAIL_WHITE, ...SOCIALS_WHITE].map((n) => (
|
||||||
))
|
<SocialCard
|
||||||
}</div>
|
url={n.url}
|
||||||
</div>;
|
image={n.icon}
|
||||||
}
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,36 @@
|
||||||
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;
|
||||||
image: string;
|
image: string;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
interface InvolveBoxState {}
|
interface InvolveBoxState {}
|
||||||
|
|
||||||
export default class InvolveBox extends Component<InvolveBoxProps, InvolveBoxState> {
|
export default class InvolveBox extends Component<
|
||||||
constructor(props: InvolveBoxProps) {
|
InvolveBoxProps,
|
||||||
super(props);
|
InvolveBoxState
|
||||||
this.state = {};
|
> {
|
||||||
}
|
constructor(props: InvolveBoxProps) {
|
||||||
|
super(props);
|
||||||
|
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">
|
||||||
<img src={this.props.image}></img>
|
<a
|
||||||
<div className="involve-description">{this.props.description}</div>
|
className="involve-title"
|
||||||
</div>;
|
href={"/" + this.props.boxTitle.toLowerCase()}
|
||||||
}
|
>
|
||||||
|
{this.props.boxTitle}
|
||||||
|
</a>
|
||||||
|
<img src={this.props.image}></img>
|
||||||
|
<div className="involve-description">
|
||||||
|
{this.props.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,28 @@
|
||||||
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;
|
||||||
image: string;
|
image: string;
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
interface SocialCardState {}
|
interface SocialCardState {}
|
||||||
|
|
||||||
export default class SocialCard extends Component<SocialCardProps, SocialCardState> {
|
export default class SocialCard extends Component<
|
||||||
constructor(props: SocialCardProps) {
|
SocialCardProps,
|
||||||
super(props);
|
SocialCardState
|
||||||
this.state = {};
|
> {
|
||||||
}
|
constructor(props: SocialCardProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {};
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <a href={this.props.url} className="social-card">
|
return (
|
||||||
<img src={this.props.image}></img>
|
<a href={this.props.url} className="social-card">
|
||||||
<div className="social-message">{this.props.message}</div>
|
<img src={this.props.image}></img>
|
||||||
</a>;
|
<div className="social-message">{this.props.message}</div>
|
||||||
}
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,56 @@
|
||||||
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;
|
||||||
backgrounds: string[];
|
backgrounds: string[];
|
||||||
delay: number;
|
delay: number;
|
||||||
}
|
}
|
||||||
interface SplashState {
|
interface SplashState {
|
||||||
progress: number;
|
progress: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Splash extends Component<SplashProps, SplashState> {
|
export default class Splash extends Component<SplashProps, SplashState> {
|
||||||
private interval: number;
|
private interval: number;
|
||||||
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"
|
||||||
<div className="call-to-action">{this.props.cta}</div>
|
style={{
|
||||||
<div className="splash-socials">{
|
backgroundImage: `url("${
|
||||||
SOCIALS_WHITE.map(n=>(
|
this.props.backgrounds[this.state.progress]
|
||||||
<a href={n.url} key={n.icon}>
|
}")`,
|
||||||
<img src={n.icon}></img>
|
}}
|
||||||
</a>
|
>
|
||||||
))
|
<div className="call-to-action">{this.props.cta}</div>
|
||||||
}</div>
|
<div className="splash-socials">
|
||||||
</div>;
|
{SOCIALS_WHITE.map((n) => (
|
||||||
}
|
<a href={n.url} key={n.icon}>
|
||||||
|
<img src={n.icon}></img>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +1,82 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Component} from "react";
|
import { Component } from "react";
|
||||||
|
|
||||||
interface TopBarProps {
|
interface TopBarProps {
|
||||||
links: {
|
links: {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
interface TopBarState {
|
interface TopBarState {
|
||||||
showBurger: boolean;
|
showBurger: boolean;
|
||||||
menuVisible: boolean;
|
menuVisible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class TopBar extends Component<TopBarProps, TopBarState> {
|
export default class TopBar extends Component<TopBarProps, TopBarState> {
|
||||||
private static HAMBURGER_POINT = 1290;
|
private static HAMBURGER_POINT = 1290;
|
||||||
constructor(props: TopBarProps) {
|
constructor(props: TopBarProps) {
|
||||||
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 (
|
||||||
this.state.showBurger ? " burger-bar" : ""
|
<div
|
||||||
}`}>
|
className={`topbar${
|
||||||
<div className="img-cont">
|
this.state.showBurger ? " burger-bar" : ""
|
||||||
<a href="/"><img src="img/logo.svg"></img></a>
|
}`}
|
||||||
<div className="burger" style={{
|
>
|
||||||
display: this.state.showBurger ? "initial" : "none"
|
<div className="img-cont">
|
||||||
}} onClick={this.toggleMenu.bind(this)} role="menubar">≡</div>
|
<a href="/">
|
||||||
</div>
|
<img src="img/logo.svg"></img>
|
||||||
<div className="links">
|
</a>
|
||||||
|
<div
|
||||||
<div className={`link-items${
|
className="burger"
|
||||||
this.state.showBurger ? " burger-time" : ""
|
style={{
|
||||||
}`} style={{display: this.state.showBurger ?
|
display: this.state.showBurger ? "initial" : "none",
|
||||||
(this.state.menuVisible ? "flex" : "none") :
|
}}
|
||||||
"initial"}}>{
|
onClick={this.toggleMenu.bind(this)}
|
||||||
this.props.links.map(l=>{
|
role="menubar"
|
||||||
return <a className="navlink" href={l.url}>{l.name}</a>
|
>
|
||||||
})
|
≡
|
||||||
}</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
<div className="links">
|
||||||
}
|
<div
|
||||||
|
className={`link-items${
|
||||||
|
this.state.showBurger ? " burger-time" : ""
|
||||||
|
}`}
|
||||||
|
style={{
|
||||||
|
display: this.state.showBurger
|
||||||
|
? this.state.menuVisible
|
||||||
|
? "flex"
|
||||||
|
: "none"
|
||||||
|
: "initial",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{this.props.links.map((l) => {
|
||||||
|
return (
|
||||||
|
<a className="navlink" href={l.url}>
|
||||||
|
{l.name}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</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,9 +403,9 @@ a:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
#cal {
|
#cal {
|
||||||
border:solid 1px #777;
|
border: solid 1px #777;
|
||||||
width: 800px;
|
width: 800px;
|
||||||
height: 600px;
|
height: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#calendar {
|
#calendar {
|
||||||
|
@ -354,6 +420,6 @@ a:hover {
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
width: 80vw;
|
width: 80vw;
|
||||||
height: 600px;
|
height: 600px;
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
}
|
}
|
|
@ -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";
|
||||||
|
@ -13,38 +13,59 @@ interface MainProps {}
|
||||||
interface MainState {}
|
interface MainState {}
|
||||||
|
|
||||||
class Main extends React.Component<MainProps, MainState> {
|
class Main extends React.Component<MainProps, MainState> {
|
||||||
constructor(props: MainProps) {
|
constructor(props: MainProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return <>
|
return (
|
||||||
<TopBar links={ACTIVE_PAGES}></TopBar>
|
<>
|
||||||
<Splash cta="Come out to our events!" delay={2000} backgrounds={["img/backgrounds/fa21social.png"]}></Splash>
|
<TopBar links={ACTIVE_PAGES}></TopBar>
|
||||||
|
<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
|
||||||
</DefaultSection>
|
src="https://calendar.google.com/calendar/embed?src=666sh64sku5n29qv2a2f4598jc%40group.calendar.google.com&ctz=America%2FLos_Angeles"
|
||||||
|
frameBorder="0"
|
||||||
|
scrolling="no"
|
||||||
|
></iframe>
|
||||||
|
</DefaultSection>
|
||||||
|
|
||||||
<DefaultSection title="Open Access Hours">
|
<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
|
||||||
</DefaultSection>
|
src="https://calendar.google.com/calendar/embed?src=c_gr3iim9ae4dv9784qkf8meb40c%40group.calendar.google.com&ctz=America%2FLos_Angeles"
|
||||||
|
frameBorder="0"
|
||||||
|
scrolling="no"
|
||||||
|
></iframe>
|
||||||
|
</DefaultSection>
|
||||||
|
|
||||||
<div id="contact-us">
|
<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) => (
|
||||||
</DefaultSection>
|
<SocialCard
|
||||||
</div>
|
url={n.url}
|
||||||
|
image={n.icon}
|
||||||
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</DefaultSection>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</>;
|
</>
|
||||||
}
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDom.render(<Main></Main>, document.getElementById("root"));
|
ReactDom.render(<Main></Main>, document.getElementById("root"));
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
|
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";
|
||||||
|
@ -13,50 +13,97 @@ interface MainProps {}
|
||||||
interface MainState {}
|
interface MainState {}
|
||||||
|
|
||||||
class Main extends React.Component<MainProps, MainState> {
|
class Main extends React.Component<MainProps, MainState> {
|
||||||
constructor(props: MainProps) {
|
constructor(props: MainProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return <>
|
return (
|
||||||
<TopBar links={ACTIVE_PAGES}></TopBar>
|
<>
|
||||||
<Splash cta="Join the 2nd largest IEEE student branch in the US!" delay={2000} backgrounds={["img/backgrounds/fa21qp.png"]}></Splash>
|
<TopBar links={ACTIVE_PAGES}></TopBar>
|
||||||
<div id="about-us">
|
<Splash
|
||||||
<DefaultSection title="We are..." paragraphs={[
|
cta="Join the 2nd largest IEEE student branch in the US!"
|
||||||
"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!",
|
delay={2000}
|
||||||
"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!"
|
backgrounds={["img/backgrounds/fa21qp.webp"]}
|
||||||
]}></DefaultSection>
|
></Splash>
|
||||||
</div>
|
<div id="about-us">
|
||||||
<div className="project-space">
|
<DefaultSection
|
||||||
<div className="ps-title">Join us at the Project Space!</div>
|
title="We are..."
|
||||||
<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>
|
paragraphs={[
|
||||||
<a className="visit-us" href="https://www.google.com/maps/@32.8817126,-117.2350998,59m/">Come visit at EBU1-4710!</a>
|
"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!",
|
||||||
</div>
|
"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 className={"involved"} title="How else can I get involved?">
|
]}
|
||||||
<div className="cards">
|
></DefaultSection>
|
||||||
<InvolveBox boxTitle="Events" image="img/backgrounds/fa21social.png" description="Meet fellow IEEE members!"></InvolveBox>
|
</div>
|
||||||
<InvolveBox boxTitle="Projects" image="img/backgrounds/robofest.png" description="Learn new skills!"></InvolveBox>
|
<div className="project-space">
|
||||||
<InvolveBox boxTitle="Committees" image="img/backgrounds/gbm.png" description="Build our amazing community!"></InvolveBox>
|
<div className="ps-title">
|
||||||
</div>
|
Join us at the Project Space!
|
||||||
</DefaultSection>
|
</div>
|
||||||
|
<p>
|
||||||
<div id="contact-us">
|
The{" "}
|
||||||
<DefaultSection title="Have questions? Contact us!">
|
<a href="https://www.google.com/maps/@32.8817126,-117.2350998,59m/">
|
||||||
<div className="join-scls">{
|
IEEE Project Space
|
||||||
[...EMAIL, ...SOCIALS].map(n => (
|
</a>{" "}
|
||||||
<SocialCard url={n.url} image={n.icon} message={n.message}></SocialCard>
|
is an open-access, collaborative space where students
|
||||||
))
|
can do homework or get access to basic electronic tools
|
||||||
}</div>
|
such as soldering stations, breadboard components, and
|
||||||
</DefaultSection>
|
Arduino and Raspberry PI parts!
|
||||||
<DefaultSection className="contact" title="Or... Contact one of our staff!">
|
</p>
|
||||||
<Carousel items={OFFICERS} itemsPerPage={6}></Carousel>
|
<a
|
||||||
</DefaultSection>
|
className="visit-us"
|
||||||
</div>
|
href="https://www.google.com/maps/@32.8817126,-117.2350998,59m/"
|
||||||
<Footer></Footer>
|
>
|
||||||
</>;
|
Come visit at EBU1-4710!
|
||||||
}
|
</a>
|
||||||
|
</div>
|
||||||
|
<DefaultSection
|
||||||
|
className={"involved"}
|
||||||
|
title="How else can I get involved?"
|
||||||
|
>
|
||||||
|
<div className="cards">
|
||||||
|
<InvolveBox
|
||||||
|
boxTitle="Events"
|
||||||
|
image="img/backgrounds/fa21social.webp"
|
||||||
|
description="Meet fellow IEEE members!"
|
||||||
|
></InvolveBox>
|
||||||
|
<InvolveBox
|
||||||
|
boxTitle="Projects"
|
||||||
|
image="img/backgrounds/robofest.webp"
|
||||||
|
description="Learn new skills!"
|
||||||
|
></InvolveBox>
|
||||||
|
<InvolveBox
|
||||||
|
boxTitle="Committees"
|
||||||
|
image="img/backgrounds/gbm.webp"
|
||||||
|
description="Build our amazing community!"
|
||||||
|
></InvolveBox>
|
||||||
|
</div>
|
||||||
|
</DefaultSection>
|
||||||
|
|
||||||
|
<div id="contact-us">
|
||||||
|
<DefaultSection title="Have questions? Contact us!">
|
||||||
|
<div className="join-scls">
|
||||||
|
{[...EMAIL, ...SOCIALS].map((n) => (
|
||||||
|
<SocialCard
|
||||||
|
url={n.url}
|
||||||
|
image={n.icon}
|
||||||
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</DefaultSection>
|
||||||
|
<DefaultSection
|
||||||
|
className="contact"
|
||||||
|
title="Or... Contact one of our staff!"
|
||||||
|
>
|
||||||
|
<Carousel items={OFFICERS} itemsPerPage={6}></Carousel>
|
||||||
|
</DefaultSection>
|
||||||
|
</div>
|
||||||
|
<Footer></Footer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDom.render(<Main></Main>, document.getElementById("root"));
|
ReactDom.render(<Main></Main>, document.getElementById("root"));
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
|
|
@ -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";
|
||||||
|
@ -13,48 +13,86 @@ interface MainProps {}
|
||||||
interface MainState {}
|
interface MainState {}
|
||||||
|
|
||||||
class Main extends React.Component<MainProps, MainState> {
|
class Main extends React.Component<MainProps, MainState> {
|
||||||
constructor(props: MainProps) {
|
constructor(props: MainProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
return <>
|
return (
|
||||||
<TopBar links={ACTIVE_PAGES}></TopBar>
|
<>
|
||||||
<Splash cta="Gain hands-on experience to make your resume stand out! No experience required!" delay={2000} backgrounds={["img/backgrounds/robocar.png"]}></Splash>
|
<TopBar links={ACTIVE_PAGES}></TopBar>
|
||||||
<DefaultSection title="RoboCup" paragraphs={[
|
<Splash
|
||||||
"\"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.\""
|
cta="Gain hands-on experience to make your resume stand out! No experience required!"
|
||||||
,"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!"
|
delay={2000}
|
||||||
]}>
|
backgrounds={["img/backgrounds/robocar.webp"]}
|
||||||
<a className='ex-link' href='https://www.robocup.org/'>RoboCup website</a>
|
></Splash>
|
||||||
</DefaultSection>
|
<DefaultSection
|
||||||
<DefaultSection title="Quarterly Projects" paragraphs={[
|
title="RoboCup"
|
||||||
"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."
|
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."',
|
||||||
<a className='ex-link' href='https://forms.gle/eW6e1i3vWCdBj7Vn6'>Apply here</a>
|
"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!",
|
||||||
</DefaultSection>
|
]}
|
||||||
<DefaultSection className={"past-proj"} title="Past Projects">
|
>
|
||||||
<div className="cards">
|
<a className="ex-link" href="https://www.robocup.org/">
|
||||||
<InvolveBox boxTitle="" image="img/backgrounds/robocar.png" description="'22 Robocar Competition"></InvolveBox>
|
RoboCup website
|
||||||
<InvolveBox boxTitle="" image="img/backgrounds/micromouse.png" description="'22 Micromouse Competition"></InvolveBox>
|
</a>
|
||||||
<InvolveBox boxTitle="" image="img/backgrounds/sp22qp.png" description="'22 Spring QP Showcase"></InvolveBox>
|
</DefaultSection>
|
||||||
</div>
|
<DefaultSection
|
||||||
</DefaultSection>
|
title="Quarterly Projects"
|
||||||
|
paragraphs={[
|
||||||
|
"Getting started on hardware development or want to make your own project? IEEE's Quarterly Projects aims to provide students with project experience in a span of 10 weeks. During QP, students will acquire skills used in the industry such as C++ and the prototyping process with the assistance of our mentors.",
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
className="ex-link"
|
||||||
|
href="https://forms.gle/eW6e1i3vWCdBj7Vn6"
|
||||||
|
>
|
||||||
|
Apply here
|
||||||
|
</a>
|
||||||
|
</DefaultSection>
|
||||||
|
<DefaultSection className={"past-proj"} title="Past Projects">
|
||||||
|
<div className="cards">
|
||||||
|
<InvolveBox
|
||||||
|
boxTitle=""
|
||||||
|
image="img/backgrounds/robocar.webp"
|
||||||
|
description="'22 Robocar Competition"
|
||||||
|
></InvolveBox>
|
||||||
|
<InvolveBox
|
||||||
|
boxTitle=""
|
||||||
|
image="img/backgrounds/micromouse.webp"
|
||||||
|
description="'22 Micromouse Competition"
|
||||||
|
></InvolveBox>
|
||||||
|
<InvolveBox
|
||||||
|
boxTitle=""
|
||||||
|
image="img/backgrounds/sp22qp.webp"
|
||||||
|
description="'22 Spring QP Showcase"
|
||||||
|
></InvolveBox>
|
||||||
|
</div>
|
||||||
|
</DefaultSection>
|
||||||
|
|
||||||
<div id="contact-us">
|
<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) => (
|
||||||
</DefaultSection>
|
<SocialCard
|
||||||
</div>
|
url={n.url}
|
||||||
|
image={n.icon}
|
||||||
|
message={n.message}
|
||||||
|
></SocialCard>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</DefaultSection>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</>;
|
</>
|
||||||
}
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDom.render(<Main></Main>, document.getElementById("root"));
|
ReactDom.render(<Main></Main>, document.getElementById("root"));
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
|
|
@ -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,73 +1,78 @@
|
||||||
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)$/,
|
{
|
||||||
use: "ts-loader"
|
test: /\.(tsx|ts)$/,
|
||||||
},
|
use: "ts-loader",
|
||||||
{
|
},
|
||||||
test: /\.(js)$/,
|
{
|
||||||
use: "babel-loader"
|
test: /\.(js)$/,
|
||||||
},
|
use: "babel-loader",
|
||||||
{
|
},
|
||||||
test: /\.css$/,
|
{
|
||||||
use: ["style-loader", "css-loader"]
|
test: /\.css$/,
|
||||||
}
|
use: ["style-loader", "css-loader"],
|
||||||
]
|
},
|
||||||
},
|
],
|
||||||
resolve: {
|
},
|
||||||
extensions: [".tsx", ".ts", ".js"],
|
resolve: {
|
||||||
},
|
extensions: [".tsx", ".ts", ".js"],
|
||||||
mode: "production",
|
},
|
||||||
plugins: [
|
mode: "production",
|
||||||
new CopyPlugin({
|
plugins: [
|
||||||
patterns: [{
|
new CopyPlugin({
|
||||||
from: "./src/public",
|
patterns: [
|
||||||
to: ".",
|
{
|
||||||
globOptions: {
|
from: "./src/public",
|
||||||
ignore: ["**/*.tsx", "**/*.ts"]
|
to: ".",
|
||||||
}
|
globOptions: {
|
||||||
}
|
ignore: ["**/*.tsx", "**/*.ts"],
|
||||||
],
|
},
|
||||||
}),
|
},
|
||||||
new LicensePlugin({
|
],
|
||||||
outputFilename: 'third-party-notice.txt'
|
}),
|
||||||
})
|
new LicensePlugin({
|
||||||
],
|
outputFilename: "third-party-notice.txt",
|
||||||
optimization: {
|
}),
|
||||||
minimize: true,
|
],
|
||||||
minimizer: [
|
optimization: {
|
||||||
new TerserPlugin({
|
minimize: true,
|
||||||
terserOptions: {
|
minimizer: [
|
||||||
output: {
|
new TerserPlugin({
|
||||||
comments: false,
|
terserOptions: {
|
||||||
},
|
output: {
|
||||||
},
|
comments: false,
|
||||||
extractComments: false,
|
},
|
||||||
}),
|
},
|
||||||
],
|
extractComments: false,
|
||||||
},
|
}),
|
||||||
//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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|