├── .env_example
├── .eslintignore
├── .eslintrc.js
├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode
└── settings.json
├── DEPLOYS.md
├── README.md
├── deploy.sh
├── jsconfig.json
├── package-lock.json
├── package.json
├── public
├── blog
│ ├── anchorfm-logo.png
│ ├── default.png
│ ├── podcast.png
│ └── video.png
├── favicon-bw.ico
├── favicon.ico
├── illustrations
│ ├── calendar.png
│ ├── coffee-chat.png
│ ├── computer.png
│ ├── get-involved.png
│ ├── hero-full.png
│ ├── hero.png
│ ├── more-events.png
│ └── wise-girls.png
├── index.html
├── logos
│ ├── se-logo-transparent.png
│ ├── se-logo-trimmed-transparent-bw.png
│ ├── se-logo-trimmed-transparent.png
│ ├── se-logo-trimmed.png
│ ├── se-logo.png
│ └── wise-logo.png
├── manifest.json
└── profiles
│ ├── aaron.jpg
│ ├── atif.jpg
│ ├── danny.jpg
│ ├── elisa.jpg
│ ├── mayank.jpg
│ ├── molly.jpg
│ └── yash.jpg
├── sesoc.code-workspace
└── src
├── App.jsx
├── App.scss
├── App.test.jsx
├── components
├── BlogPostsGroup.jsx
├── BlogSocialLinks.jsx
├── ComingSoon.jsx
├── EventCalendar.jsx
├── EventList.jsx
├── Footer.jsx
├── Meetings.jsx
├── NavigationBar.jsx
├── NewsList.jsx
├── Platform.jsx
├── ProfilePhotoGroup.jsx
├── PromptActionButtons.jsx
└── styles
│ ├── BlogPostsGroup.scss
│ ├── BlogSocialLinks.scss
│ ├── EventCalendar.scss
│ ├── EventList.scss
│ ├── Footer.scss
│ ├── Meetings.scss
│ ├── NavigationBar.scss
│ ├── NewsList.scss
│ ├── ProfilePhotoGroup.scss
│ ├── PromptActionButtons.scss
│ └── ReactBigCalendar.scss
├── containers
├── About.jsx
├── Blog.jsx
├── Events.jsx
├── GetInvolved.jsx
├── Home.jsx
├── Sponsors.jsx
├── Wise.jsx
└── styles
│ ├── Events.scss
│ ├── GetInvolved.scss
│ ├── Home.scss
│ └── Wise.scss
├── content
└── BlogContent.js
├── index.css
├── index.js
├── modules
└── gcal.js
├── serviceWorker.js
└── styles
└── _colors.scss
/.env_example:
--------------------------------------------------------------------------------
1 | REACT_APP_GOOGLE_CALENDAR_ID='CALENDAR_ID_GOES_HERE'
2 | REACT_APP_GOOGLE_CALENDAR_API_KEY='API_KEY_GOES_HERE'
3 |
4 | REACT_APP_GOOGLE_CALENDAR_ID_WISE='CALENDAR_ID_GOES_HERE'
5 | REACT_APP_GOOGLE_CALENDAR_API_KEY_WISE='API_KEY_GOES_HERE'
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/node_modules/**
2 | public/**
3 | build/**
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | node: true,
4 | es6: true,
5 | },
6 | parser: "babel-eslint",
7 | parserOptions: {
8 | sourceType: "module",
9 | },
10 | settings: {
11 | react: {
12 | createClass: "createReactClass",
13 | pragma: "React",
14 | version: "detect",
15 | flowVersion: "0.53",
16 | },
17 | linkComponents: [
18 | { name: "Link", linkAttribute: "to" },
19 | { name: "OutboundLink", linkAttribute: "to" },
20 | ],
21 | },
22 | rules: {
23 | "no-console": "warn",
24 | "no-param-reassign": "error",
25 | "react/jsx-key": ["off"],
26 | },
27 | // Use prettier for code formatting and eslint soley for linting
28 | extends: ["eslint:recommended", "plugin:react/recommended", "prettier"],
29 | };
30 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: SE Soc CI
5 | on:
6 | pull_request:
7 |
8 | jobs:
9 | lint:
10 | name: Lint
11 |
12 | runs-on: ubuntu-latest
13 |
14 | strategy:
15 | matrix:
16 | node-version: [12.x]
17 |
18 | steps:
19 | - uses: actions/checkout@v2
20 | - name: Use Node.js ${{ matrix.node-version }}
21 | uses: actions/setup-node@v1
22 | with:
23 | node-version: ${{ matrix.node-version }}
24 | - run: npm ci
25 | - run: npm run ci_format
26 | env:
27 | CI: true
28 | build:
29 | name: Build App
30 |
31 | runs-on: ubuntu-latest
32 |
33 | strategy:
34 | matrix:
35 | node-version: [12.x]
36 |
37 | steps:
38 | - uses: actions/checkout@v2
39 | - name: Use Node.js ${{ matrix.node-version }}
40 | uses: actions/setup-node@v1
41 | with:
42 | node-version: ${{ matrix.node-version }}
43 | - run: npm ci
44 | - run: npm run build --if-present
45 | env:
46 | CI: true
47 | test:
48 | name: Run Tests
49 |
50 | runs-on: ubuntu-latest
51 |
52 | strategy:
53 | matrix:
54 | node-version: [12.x]
55 |
56 | steps:
57 | - uses: actions/checkout@v2
58 | - name: Use Node.js ${{ matrix.node-version }}
59 | uses: actions/setup-node@v1
60 | with:
61 | node-version: ${{ matrix.node-version }}
62 | - run: npm ci
63 | - run: npm test
64 | env:
65 | CI: true
66 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | #firebase stuff
13 | #.firebaserc
14 | #firebase.json
15 |
16 | # misc
17 | **/.DS_Store
18 | .env
19 | .env.local
20 | .env.development.local
21 | .env.test.local
22 | .env.production.local
23 |
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # Add all file/file extensions to be ignored by prettier here
2 | *.md
3 | *.html
4 | src/assets/*
5 | package-lock.json
6 | jsconfig.json
7 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "all",
3 | "tabWidth": 2,
4 | "semi": false,
5 | "singleQuote": true,
6 | "jsxBracketSameLine": false,
7 | "arrowParens": "always",
8 | "bracketSpacing": true
9 | }
10 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnPaste": true,
3 | "editor.formatOnType": true
4 | }
5 |
--------------------------------------------------------------------------------
/DEPLOYS.md:
--------------------------------------------------------------------------------
1 | # Some important information about Deploying to CSC servers #
2 | - CSC uses Apache
3 | - the .htaccess in sesoc/www folder is needed. Please don't clear the directory, otherwise you need to make a new .htaccess file within sesoc/www with the following contents:
4 | ```
5 | Options -MultiViews
6 | RewriteEngine On
7 | RewriteCond %{REQUEST_FILENAME} !-f
8 | RewriteRule ^ index.html [QSA,L]
9 | ```
10 |
11 | # Steps to Deploy (if not using the deploy.sh script) #
12 | 1. login to any CSC server
13 | 2. cd to the sesoc's subdirectory in users
14 | 3. ```become_club sesoc```
15 | 4. ```cd public-website```
16 | 5. ```./deploy.sh``` (and follow any instructions given)
17 | 6. done!
18 |
19 |
20 | # Steps to Deploy (if not using the deploy.sh script) #
21 | 1. login to any CSC server
22 | 2. cd to the sesoc's subdirectory in users
23 | 3. ```become_club sesoc```
24 | 4. ```cd public-website```
25 | 5. ```git pull``` (may need to login with github credentials)
26 | 6. ```npm install```
27 | 7. ```npm run build```
28 | 8. ```cp -r build/* ../www```
29 | 9. done!
30 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | git pull
3 | npm install
4 | npm run build
5 | cp -r build/* ../www
6 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "src",
5 | "strictNullChecks": true,
6 | "noUnusedLocals": true,
7 | "noImplicitThis": true,
8 | "noFallthroughCasesInSwitch": true,
9 | "allowUnreachableCode": false
10 | },
11 | "include": ["src", "jsconfig.json"]
12 | }
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "public-website",
4 | "homepage": "https://sesoc.uwaterloo.ca/",
5 | "version": "0.1.0",
6 | "scripts": {
7 | "build": "react-scripts build",
8 | "ci_format": "prettier-eslint --list-different --log-level error $PWD/\"**/*.js\" $PWD/\"**/*.jsx\" && eslint \"**/*.js\" \"**/*.jsx\" && prettier-package-json --list-different --tab-width 2 ./package.json",
9 | "eject": "react-scripts eject",
10 | "format": "prettier-eslint $PWD/\"**/*.js\" $PWD/\"**/*.jsx\" --write && eslint \"**/*.js\" \"**/*.jsx\" --fix && prettier-package-json --write --tab-width 2 ./package.json",
11 | "lint": "eslint \"**/*.js\" \"**/*.jsx\" --fix",
12 | "start": "react-scripts start",
13 | "test": "react-scripts test"
14 | },
15 | "dependencies": {
16 | "ajv": "^6.10.0",
17 | "bootstrap": "^4.5.0",
18 | "lodash": "^4.17.19",
19 | "node-sass": "^4.14.1",
20 | "react": "next",
21 | "react-big-calendar": "^0.24.6",
22 | "react-bootstrap": "^1.0.0-beta.9",
23 | "react-dom": "next",
24 | "react-router-dom": "^5.2.0",
25 | "react-scripts": "4.0.2",
26 | "url": "^0.11.0"
27 | },
28 | "devDependencies": {
29 | "axios": "^0.21.1",
30 | "eslint-config-prettier": "^7.2.0",
31 | "moment": "^2.26.0",
32 | "prettier-eslint": "^12.0.0",
33 | "prettier-eslint-cli": "^5.0.0",
34 | "prettier-package-json": "2.1.3"
35 | },
36 | "browserslist": [
37 | ">0.2%",
38 | "not dead",
39 | "not ie <= 11",
40 | "not op_mini all"
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/public/blog/anchorfm-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/blog/anchorfm-logo.png
--------------------------------------------------------------------------------
/public/blog/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/blog/default.png
--------------------------------------------------------------------------------
/public/blog/podcast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/blog/podcast.png
--------------------------------------------------------------------------------
/public/blog/video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/blog/video.png
--------------------------------------------------------------------------------
/public/favicon-bw.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/favicon-bw.ico
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/favicon.ico
--------------------------------------------------------------------------------
/public/illustrations/calendar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/calendar.png
--------------------------------------------------------------------------------
/public/illustrations/coffee-chat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/coffee-chat.png
--------------------------------------------------------------------------------
/public/illustrations/computer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/computer.png
--------------------------------------------------------------------------------
/public/illustrations/get-involved.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/get-involved.png
--------------------------------------------------------------------------------
/public/illustrations/hero-full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/hero-full.png
--------------------------------------------------------------------------------
/public/illustrations/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/hero.png
--------------------------------------------------------------------------------
/public/illustrations/more-events.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/more-events.png
--------------------------------------------------------------------------------
/public/illustrations/wise-girls.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/wise-girls.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
31 | SE Soc
32 |
33 |
34 |
35 |
36 | You need to enable JavaScript to run this app.
37 |
38 |
39 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/public/logos/se-logo-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo-transparent.png
--------------------------------------------------------------------------------
/public/logos/se-logo-trimmed-transparent-bw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo-trimmed-transparent-bw.png
--------------------------------------------------------------------------------
/public/logos/se-logo-trimmed-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo-trimmed-transparent.png
--------------------------------------------------------------------------------
/public/logos/se-logo-trimmed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo-trimmed.png
--------------------------------------------------------------------------------
/public/logos/se-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo.png
--------------------------------------------------------------------------------
/public/logos/wise-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/wise-logo.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "SE Society",
3 | "name": "University of Waterloo Software Engineering Society",
4 | "icons": [{
5 | "src": "favicon-bw.ico",
6 | "sizes": "64x64 32x32 24x24 16x16",
7 | "type": "image/x-icon"
8 | }],
9 | "start_url": ".",
10 | "display": "standalone",
11 | "theme_color": "#000000",
12 | "background_color": "#ffffff"
13 | }
--------------------------------------------------------------------------------
/public/profiles/aaron.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/aaron.jpg
--------------------------------------------------------------------------------
/public/profiles/atif.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/atif.jpg
--------------------------------------------------------------------------------
/public/profiles/danny.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/danny.jpg
--------------------------------------------------------------------------------
/public/profiles/elisa.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/elisa.jpg
--------------------------------------------------------------------------------
/public/profiles/mayank.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/mayank.jpg
--------------------------------------------------------------------------------
/public/profiles/molly.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/molly.jpg
--------------------------------------------------------------------------------
/public/profiles/yash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/yash.jpg
--------------------------------------------------------------------------------
/sesoc.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "."
5 | }
6 | ],
7 | "settings": {
8 | "eslint.workingDirectories": [
9 | {
10 | "mode": "auto"
11 | }
12 | ],
13 | "files.trimTrailingWhitespace": true,
14 | "files.insertFinalNewline": true,
15 | "editor.tabSize": 2,
16 | "editor.defaultFormatter": "esbenp.prettier-vscode",
17 | "editor.formatOnSave": true,
18 | "[javascript, javascriptreact]": {
19 | "editor.defaultFormatter": "esbenp.prettier-vscode",
20 | "editor.formatOnSave": true
21 | },
22 | "files.exclude": {
23 | "css": true,
24 | "scss": true,
25 | "ejs": true,
26 | "node_modules": true,
27 | "**/.DS_Store": true
28 | },
29 | "css.validate": false,
30 | "files.autoSave": "onFocusChange"
31 | },
32 | "extensions": {
33 | "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
3 |
4 | import Home from 'containers/Home'
5 | import Events from 'containers/Events'
6 | import About from 'containers/About'
7 | import GetInvolved from 'containers/GetInvolved'
8 | import Blog from 'containers/Blog'
9 | import Wise from 'containers/Wise'
10 | import NavigationBar from 'components/NavigationBar'
11 | import 'App.scss'
12 |
13 | class App extends Component {
14 | render() {
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | )
30 | }
31 | }
32 |
33 | export default App
34 |
--------------------------------------------------------------------------------
/src/App.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/colors';
2 |
3 | :root {
4 | --color-eng: #{$color-eng};
5 | --color-math: #{$color-math};
6 | }
7 |
8 | .App {
9 | text-align: center;
10 | }
11 |
12 | .App-logo {
13 | animation: App-logo-spin infinite 20s linear;
14 | height: 40vmin;
15 | }
16 |
17 | .App-header {
18 | background-color: #282c34;
19 | min-height: 100vh;
20 | display: flex;
21 | flex-direction: column;
22 | align-items: center;
23 | justify-content: center;
24 | font-size: calc(10px + 2vmin);
25 | color: white;
26 | }
27 |
28 | .App-link {
29 | color: #61dafb;
30 | }
31 |
32 | @keyframes App-logo-spin {
33 | from {
34 | transform: rotate(0deg);
35 | }
36 | to {
37 | transform: rotate(360deg);
38 | }
39 | }
40 |
41 | /* Navbar styling */
42 |
43 | a {
44 | margin-top: 0em;
45 | color: $color-eng;
46 | }
47 |
48 | .primary-nav {
49 | float: right;
50 | margin-left: auto;
51 | margin-right: 0;
52 | text-align: right;
53 | }
54 |
55 | /* Site-wide styling */
56 |
57 | h1 {
58 | color: $color-primary;
59 | font-family: 'Poppins', sans-serif;
60 | font-weight: 700;
61 | }
62 |
63 | h2 {
64 | font-family: 'Poppins', sans-serif;
65 | font-weight: 500;
66 | }
67 |
68 | h3 {
69 | font-family: 'Poppins', sans-serif;
70 | font-weight: 400;
71 | }
72 |
73 | p {
74 | color: $color-primary;
75 | font-family: 'Poppins', sans-serif;
76 | font-weight: 400;
77 | }
78 |
79 | .center {
80 | text-align: center;
81 | }
82 |
83 | .container {
84 | margin-top: 0px;
85 | width: 100%;
86 | overflow: hidden;
87 | }
88 |
89 | /*
90 | `footer-to-bottom` wraps the body and footer for each page.
91 | It spaces the two containers out so that the footer is pushed
92 | to the bottom of the view if the body contents do not fill up
93 | the whole view. Otherwise, the footer will rest below the
94 | body content.
95 | */
96 |
97 | .footer-to-bottom {
98 | display: flex;
99 | min-height: calc(100vh - 60.59px); /* Total view height - navbar height */
100 | flex-direction: column;
101 | justify-content: space-between;
102 | }
103 |
104 | a:hover {
105 | color: $color-math-light;
106 | }
107 |
--------------------------------------------------------------------------------
/src/App.test.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | import React from 'react'
3 | import ReactDOM from 'react-dom'
4 | import App from './App'
5 |
6 | it('renders without crashing', () => {
7 | const div = document.createElement('div')
8 | ReactDOM.render( , div)
9 | ReactDOM.unmountComponentAtNode(div)
10 | })
11 |
--------------------------------------------------------------------------------
/src/components/BlogPostsGroup.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import url from 'url'
3 | import PropTypes from 'prop-types'
4 | import { Card, Col, Row } from 'react-bootstrap'
5 | import BlogSocialLinks from 'components/BlogSocialLinks'
6 | import { BLOG_TYPES, BLOG_ICONS_MAP } from 'content/BlogContent'
7 | import 'components/styles/BlogPostsGroup.scss'
8 |
9 | const getDefaultImage = (type) =>
10 | url.resolve(process.env.PUBLIC_URL, `/blog/${BLOG_ICONS_MAP.get(type)}`)
11 |
12 | const BlogTile = ({ color, type, title, image, links }) => {
13 | const imgSrc = image || getDefaultImage(type)
14 | const defaultLink = links.find(
15 | (link) => link.type === 'default' || link.type === 'spotify',
16 | )
17 |
18 | return (
19 |
20 |
21 |
27 |
28 | {title}
29 |
30 |
31 |
32 | )
33 | }
34 |
35 | BlogTile.propTypes = {
36 | color: PropTypes.string.isRequired,
37 | type: PropTypes.oneOf(Object.values(BLOG_TYPES)),
38 | title: PropTypes.string.isRequired,
39 | image: PropTypes.string,
40 | links: PropTypes.arrayOf(
41 | PropTypes.shape({
42 | type: PropTypes.string,
43 | link: PropTypes.oneOf(['default', PropTypes.string]),
44 | }),
45 | ).isRequired,
46 | }
47 |
48 | BlogTile.defaultProps = {
49 | image: null,
50 | }
51 |
52 | const BlogTileRow = ({ blogPosts, color }) => {
53 | if (!blogPosts) return null
54 | return (
55 |
56 | {blogPosts.map((blog) => (
57 |
58 | ))}
59 |
60 | )
61 | }
62 |
63 | BlogTileRow.propTypes = {
64 | blogPosts: PropTypes.arrayOf(PropTypes.object).isRequired,
65 | color: PropTypes.string.isRequired,
66 | }
67 |
68 | class BlogPostsGroup extends Component {
69 | render() {
70 | const { blogPosts, month, color } = this.props
71 |
72 | return (
73 |
74 |
75 | {month}
76 |
77 |
78 |
79 |
80 |
81 | )
82 | }
83 | }
84 |
85 | BlogPostsGroup.propTypes = {
86 | blogPosts: PropTypes.arrayOf(PropTypes.object).isRequired,
87 | month: PropTypes.string.isRequired,
88 | color: PropTypes.string.isRequired,
89 | }
90 |
91 | export default BlogPostsGroup
92 |
--------------------------------------------------------------------------------
/src/components/BlogSocialLinks.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import url from 'url'
3 | import PropTypes from 'prop-types'
4 | import 'components/styles/BlogSocialLinks.scss'
5 |
6 | const anchorLogoSrc = url.resolve(
7 | process.env.PUBLIC_URL,
8 | '/blog/anchorfm-logo.png',
9 | )
10 |
11 | export const LINK_ICON_MAP = {
12 | default: ,
13 | spotify: ,
14 | apple: ,
15 | anchor: ,
16 | rss: ,
17 | }
18 |
19 | const BlogSocialLinks = ({ type, links }) => {
20 | if (type === 'Podcast') {
21 | const linksToRender = links.filter(({ type }) => type !== 'default')
22 | return (
23 |
32 | )
33 | }
34 |
35 | const [{ link, type: linkType }] = links
36 | return (
37 |
42 | )
43 | }
44 |
45 | BlogSocialLinks.propTypes = {
46 | links: PropTypes.arrayOf(
47 | PropTypes.shape({
48 | type: PropTypes.string,
49 | link: PropTypes.oneOf(['default', 'spotify', 'apple', 'anchor', 'rss']),
50 | }),
51 | ).isRequired,
52 | type: PropTypes.string.isRequired,
53 | }
54 |
55 | export default BlogSocialLinks
56 |
--------------------------------------------------------------------------------
/src/components/ComingSoon.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import url from 'url'
3 |
4 | const logo = url.resolve(process.env.PUBLIC_URL, '/logos/se-logo-trimmed.png')
5 |
6 | class ComingSoon extends Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 | Coming soon.
13 |
14 |
15 | )
16 | }
17 | }
18 |
19 | export default ComingSoon
20 |
--------------------------------------------------------------------------------
/src/components/EventCalendar.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import { Row, Col, Button } from 'react-bootstrap'
4 | import { Calendar, momentLocalizer } from 'react-big-calendar'
5 | import Toolbar from 'react-big-calendar/lib/Toolbar'
6 | import Moment from 'moment'
7 | import 'components/styles/ReactBigCalendar.scss'
8 | import 'components/styles/EventCalendar.scss'
9 |
10 | const localizer = momentLocalizer(Moment)
11 |
12 | class CalendarToolbar extends Toolbar {
13 | render() {
14 | let {
15 | localizer: { messages },
16 | label,
17 | } = this.props
18 |
19 | return (
20 |
21 |
22 |
23 |
28 | Today
29 |
30 |
31 |
32 |
33 |
38 | ←
39 |
40 |
{label}
41 |
46 | →
47 |
48 |
49 |
50 | {this.viewNamesGroup(messages)}
51 |
52 |
53 | )
54 | }
55 |
56 | navigate = (action) => {
57 | this.props.onNavigate(action)
58 | }
59 |
60 | view = (view) => {
61 | this.props.onView(view)
62 | }
63 |
64 | viewNamesGroup(messages) {
65 | let viewNames = this.props.views
66 |
67 | if (viewNames.length > 1) {
68 | return viewNames.map((name) => (
69 |
75 | {messages[name]}
76 |
77 | ))
78 | }
79 | }
80 | }
81 |
82 | CalendarToolbar.propTypes = {
83 | view: PropTypes.string.isRequired,
84 | views: PropTypes.arrayOf(PropTypes.string).isRequired,
85 | label: PropTypes.node.isRequired,
86 | localizer: PropTypes.object,
87 | onNavigate: PropTypes.func.isRequired,
88 | onView: PropTypes.func.isRequired,
89 | }
90 |
91 | const CalendarEventWrapper = ({ event, children }) => (
92 |
93 | {children}
94 |
95 | )
96 |
97 | CalendarEventWrapper.propTypes = {
98 | event: PropTypes.objectOf({
99 | link: PropTypes.string.isRequired,
100 | }),
101 | children: PropTypes.node.isRequired,
102 | }
103 |
104 | const EventCalendar = (props) => {
105 | return (
106 | {
109 | event.start = Moment(event.start).toDate()
110 | event.end = Moment(event.end).toDate()
111 | return event
112 | })}
113 | components={{
114 | eventWrapper: CalendarEventWrapper,
115 | toolbar: CalendarToolbar,
116 | }}
117 | startAccessor="start"
118 | endAccessor="end"
119 | views={['month', 'day']}
120 | defaultDate={Moment().toDate()}
121 | />
122 | )
123 | }
124 |
125 | EventCalendar.propTypes = {
126 | events: PropTypes.arrayOf(PropTypes.object).isRequired,
127 | }
128 |
129 | export default EventCalendar
130 |
--------------------------------------------------------------------------------
/src/components/EventList.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import PropTypes from 'prop-types'
3 | import url from 'url'
4 | import 'components/styles/EventList.scss'
5 |
6 | const moreEvents = url.resolve(
7 | process.env.PUBLIC_URL,
8 | '/illustrations/more-events.png',
9 | )
10 |
11 | const Event = (props) => (
12 |
28 | )
29 |
30 | Event.propTypes = {
31 | event: PropTypes.object.isRequired,
32 | }
33 |
34 | class EventList extends Component {
35 | render() {
36 | return (
37 |
38 |
Upcoming Events
39 | {this.props.upcomingEvents && this.props.upcomingEvents.length ? (
40 |
41 |
42 |
43 | {this.props.upcomingEvents.map((event, index) => (
44 |
45 |
46 |
47 |
48 |
49 | ))}
50 |
51 |
52 |
53 | ) : (
54 |
55 |
60 |
61 | )}
62 |
63 | )
64 | }
65 | }
66 |
67 | EventList.propTypes = {
68 | upcomingEvents: PropTypes.arrayOf(PropTypes.object).isRequired,
69 | }
70 |
71 | export default EventList
72 |
--------------------------------------------------------------------------------
/src/components/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import PropTypes from 'prop-types'
3 | import 'components/styles/Footer.scss'
4 |
5 | class Footer extends Component {
6 | render() {
7 | return (
8 |
29 | )
30 | }
31 | }
32 |
33 | Footer.propTypes = {
34 | color: PropTypes.string.isRequired,
35 | }
36 |
37 | export default Footer
38 |
--------------------------------------------------------------------------------
/src/components/Meetings.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import PropTypes from 'prop-types'
3 | import { Row, Col, Button } from 'react-bootstrap'
4 | import 'components/styles/Meetings.scss'
5 |
6 | const Meeting = (props) => (
7 |
8 |
9 |
10 | {props.meeting.title}
11 |
12 | {props.meeting.date}
13 | {props.meeting.time}
14 | {props.meeting.location}
15 |
16 | {props.meeting.link ? (
17 |
18 |
24 |
25 | ) : (
26 |
27 | The meeting agenda will be posted soon! Stay tuned.
28 |
29 | )}
30 |
31 | )
32 |
33 | Meeting.propTypes = {
34 | meeting: PropTypes.object.isRequired,
35 | }
36 |
37 | class Meetings extends Component {
38 | render() {
39 | return (
40 |
41 | {this.props.meetings.map((meeting) => (
42 |
43 | ))}
44 |
45 |
46 |
47 | Take a look at our past initiatives by reading our previous
48 | meeting notes.
49 |
50 |
51 |
52 |
58 | Meetings Archive
59 |
60 |
61 |
62 |
63 | )
64 | }
65 | }
66 |
67 | Meetings.propTypes = {
68 | meetings: PropTypes.arrayOf(PropTypes.object).isRequired,
69 | archiveLink: PropTypes.string.isRequired,
70 | }
71 |
72 | export default Meetings
73 |
--------------------------------------------------------------------------------
/src/components/NavigationBar.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import url from 'url'
3 | import { Container, Nav, Navbar } from 'react-bootstrap'
4 | import { Link, NavLink, useLocation } from 'react-router-dom'
5 | import 'components/styles/NavigationBar.scss'
6 |
7 | const logo = url.resolve(
8 | process.env.PUBLIC_URL,
9 | '/logos/se-logo-trimmed-transparent-bw.png',
10 | )
11 |
12 | const NavigationBar = () => {
13 | let location = useLocation()
14 | let color = ''
15 | switch (location.pathname) {
16 | case '/':
17 | color = '#F0EDF1'
18 | break
19 | default:
20 | color = 'transparent'
21 | break
22 | }
23 |
24 | return (
25 |
26 |
27 |
28 |
34 |
35 |
42 |
43 |
44 |
51 | Home
52 |
53 |
60 | About
61 |
62 |
69 | Events
70 |
71 |
78 | Get Involved
79 |
80 |
87 | Blog
88 |
89 |
96 | WiSE
97 |
98 |
99 |
100 |
101 |
102 | )
103 | }
104 |
105 | // Props from withRouter HOC
106 | NavigationBar.propTypes = {}
107 |
108 | export default NavigationBar
109 |
--------------------------------------------------------------------------------
/src/components/NewsList.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import 'components/styles/NewsList.scss'
4 |
5 | const NewsContent = (props) => {
6 | const numEntries = props.numEntries ? props.numEntries : props.articles.length
7 |
8 | return props.articles.slice(0, numEntries).map((article) => (
9 |
10 |
11 |
12 | {article.title}
13 | {article.description}
14 |
15 |
16 |
17 | ))
18 | }
19 |
20 | const NewsList = (props) => (
21 |
22 |
news
23 |
24 |
25 | )
26 |
27 | NewsList.propTypes = {
28 | articles: PropTypes.arrayOf({
29 | link: PropTypes.string.isRequired,
30 | title: PropTypes.string.isRequired,
31 | description: PropTypes.string.isRequired,
32 | }),
33 | numEntries: PropTypes.number,
34 | }
35 |
36 | export default NewsList
37 |
--------------------------------------------------------------------------------
/src/components/Platform.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import React, { Component } from 'react'
3 | import PropTypes from 'prop-types'
4 |
5 | function Points(props) {
6 | const listItems = props.points.map((point) => (
7 |
8 | {point}
9 |
10 | ))
11 | return (
12 |
16 | )
17 | }
18 |
19 | function Picture(props) {
20 | return (
21 |
22 |
23 |
24 |
29 |
30 |
31 |
32 | )
33 | }
34 |
35 | function Achievements(props) {
36 | if (props.achievements) {
37 | const listItems = props.achievements.map((achievement) => (
38 |
39 | {achievement}
40 |
41 | ))
42 | return (
43 |
44 |
Achievements:
45 |
46 |
47 | )
48 | } else {
49 | return
50 | }
51 | }
52 |
53 | class Platform extends Component {
54 | render() {
55 | return (
56 |
57 |
58 | {'Candidates for ' + this.props.platform.candidacy}
59 |
60 |
61 |
62 |
63 | {this.props.platform.name}
64 |
68 |
69 |
70 |
71 |
{this.props.platform.platform}
72 |
73 |
74 |
75 |
76 |
77 |
78 | )
79 | }
80 | }
81 |
82 | Platform.propTypes = {
83 | platform: PropTypes.shape({
84 | name: PropTypes.string.isRequired,
85 | candidacy: PropTypes.string.isRequired,
86 | platform: PropTypes.string.isRequired,
87 | quote: PropTypes.string.isRequired,
88 | points: PropTypes.arrayOf(PropTypes.string.isRequired),
89 | contacts: PropTypes.shape({
90 | facebook: PropTypes.string,
91 | email: PropTypes.string,
92 | }),
93 | image: PropTypes.string.isRequired,
94 | achievements: PropTypes.arrayOf(PropTypes.string),
95 | }),
96 | }
97 |
98 | export default Platform
99 |
--------------------------------------------------------------------------------
/src/components/ProfilePhotoGroup.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import PropTypes from 'prop-types'
3 | import { Card, Col, Row } from 'react-bootstrap'
4 | import 'components/styles/ProfilePhotoGroup.scss'
5 |
6 | const Image = (props) => (
7 |
8 |
9 |
13 |
14 | {props.person.name}
15 |
16 | {props.person.year}
17 |
18 | {props.person.position}
19 |
20 |
21 |
22 |
23 |
24 | )
25 |
26 | Image.propTypes = {
27 | color: PropTypes.string.isRequired,
28 | person: PropTypes.object.isRequired,
29 | }
30 |
31 | const ImageRow = (props) => {
32 | const listItems = props.people
33 | ? props.people.map((person) => (
34 |
35 | ))
36 | : null
37 | return listItems
38 | }
39 |
40 | class ProfilePhotoGroup extends Component {
41 | render() {
42 | const execs = this.props.execs
43 | const reps = this.props.reps
44 | const soc = this.props.soc
45 | const color = this.props.color
46 | return (
47 |
48 | {reps && reps.length ? (
49 | <>
50 |
{soc}
51 |
Execs
52 | >
53 | ) : (
54 |
{soc} Execs
55 | )}
56 |
57 |
58 |
59 | {reps && reps.length ?
Reps
: null}
60 | {reps && reps.length ? (
61 |
62 |
63 |
64 | ) : null}
65 |
66 | )
67 | }
68 | }
69 |
70 | ProfilePhotoGroup.propTypes = {
71 | soc: PropTypes.string.isRequired,
72 | execs: PropTypes.arrayOf(PropTypes.object).isRequired,
73 | reps: PropTypes.arrayOf(PropTypes.object).isRequired,
74 | color: PropTypes.string.isRequired,
75 | }
76 |
77 | export default ProfilePhotoGroup
78 |
--------------------------------------------------------------------------------
/src/components/PromptActionButtons.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import PropTypes from 'prop-types'
3 | import { Button } from 'react-bootstrap'
4 | import 'components/styles/PromptActionButtons.scss'
5 |
6 | // Prompt Text + Action Button
7 | // eg. Have an event in mind? [Suggest an Event]
8 | const Action = (props) => (
9 | <>
10 | {props.action.prompt}
11 |
17 | {props.action.buttonText}
18 |
19 | >
20 | )
21 |
22 | Action.propTypes = {
23 | action: PropTypes.object.isRequired,
24 | }
25 |
26 | class PromptActionButtons extends Component {
27 | render() {
28 | return (
29 |
30 | {this.props.actions.map((action, index) => (
31 |
32 | ))}
33 |
34 | )
35 | }
36 | }
37 |
38 | PromptActionButtons.propTypes = {
39 | actions: PropTypes.arrayOf(PropTypes.object).isRequired,
40 | }
41 |
42 | export default PromptActionButtons
43 |
--------------------------------------------------------------------------------
/src/components/styles/BlogPostsGroup.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 |
3 | .blog-month {
4 | text-align: center;
5 | padding-top: 6.5rem;
6 | }
7 |
8 | .blog-row {
9 | display: grid;
10 | margin: 0;
11 | grid-template-columns: repeat(3, 1fr);
12 | grid-gap: 40px;
13 | margin-bottom: 40px;
14 | }
15 |
16 | .card {
17 | border-radius: 6px;
18 | overflow: hidden;
19 | border-width: 0px;
20 | width: 100%;
21 | height: 100%;
22 | padding: 0;
23 | margin: 0;
24 |
25 | a {
26 | text-decoration: none;
27 | height: 100%;
28 | display: flex;
29 | flex-direction: column;
30 | justify-content: center;
31 | }
32 | }
33 |
34 | .card-img-container {
35 | position: relative;
36 | }
37 |
38 | .card-img-hover {
39 | opacity: 0;
40 | position: absolute;
41 | top: 0;
42 | height: 100%;
43 | width: 100%;
44 | transition: 0.5s ease;
45 | background: rgba(0, 0, 0, 0.7);
46 | }
47 |
48 | .card-img-container:hover .card-img-hover {
49 | opacity: 1;
50 | }
51 |
52 | .card-img {
53 | padding: 0px;
54 | margin: 0px;
55 | object-fit: cover;
56 | object-position: center;
57 | max-height: 200px;
58 | width: 100%;
59 | border-radius: 0;
60 | }
61 |
62 | .card-body {
63 | padding: 10px 14px !important;
64 | margin: 0 !important;
65 | background-color: $color-eng;
66 | color: white;
67 | text-align: left;
68 | align-items: center;
69 | display: flex;
70 | font-size: 14px;
71 | line-height: 20px;
72 | height: calc(100% - height('.card-img'));
73 | }
74 |
75 | @media screen and (max-width: 991px) {
76 | .blog-row {
77 | grid-template-columns: repeat(2, 1fr);
78 | grid-gap: 30px;
79 | margin-bottom: 30px;
80 | }
81 |
82 | .card-body {
83 | font-size: 12px;
84 | }
85 | }
86 |
87 | @media screen and (max-width: 768px) {
88 | .blog-month {
89 | text-align: left;
90 | padding: 1rem 0;
91 | }
92 |
93 | .card-img {
94 | max-height: 140px;
95 | }
96 | }
97 |
98 | @media screen and (max-width: 370px) {
99 | .blog-row {
100 | grid-template-columns: 1fr;
101 | grid-gap: 20px;
102 | margin-bottom: 20px;
103 | }
104 |
105 | .card-img {
106 | max-height: 200px;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/components/styles/BlogSocialLinks.scss:
--------------------------------------------------------------------------------
1 | .social-links-container {
2 | display: flex;
3 | justify-content: center;
4 | align-items: center;
5 | width: 100%;
6 | height: 100%;
7 |
8 | a {
9 | color: white !important;
10 | }
11 |
12 | .fab, .fas {
13 | font-size: 40px;
14 | }
15 |
16 | img {
17 | max-height: 40px;
18 | width: auto;
19 | }
20 | }
21 |
22 | .social-links-grid {
23 | display: grid;
24 | grid-template-columns: auto auto;
25 | grid-gap: 20px;
26 | justify-content: center;
27 | align-items: center;
28 | }
--------------------------------------------------------------------------------
/src/components/styles/EventCalendar.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 | .cal-c {
3 | margin-top: 25px;
4 | margin-bottom: 20px;
5 | }
6 |
7 | .cal-tb-btn {
8 | background-color: white;
9 | color: white;
10 | }
11 |
12 | .cal-tb-nav {
13 | width: fit-content;
14 | margin-left: auto;
15 | margin-right: auto;
16 | display: table;
17 | }
18 |
19 | .cal-date {
20 | display: table-cell;
21 | text-align: center;
22 | color: $color-eng;
23 | }
24 |
25 | .cal-tb-nav-bf {
26 | background-color: white;
27 | color: $color-eng;
28 | border-width: 0px;
29 | }
30 |
31 | .cal-tb-btn {
32 | background-color: white;
33 | color: $color-eng;
34 | border-width: 0px;
35 | }
36 |
37 | .cal-tb-btn:hover {
38 | background-color: $color-eng-lightest;
39 | color: $color-eng;
40 | border-width: 0px;
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/styles/EventList.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 | .event-list tr .accent {
3 | color: $color-eng;
4 | }
5 |
6 | .event {
7 | padding-bottom: 20px;
8 | }
9 |
10 | .event-title {
11 | margin-bottom: 0px;
12 | }
13 |
14 | .scroll {
15 | height: auto;
16 | max-height: 525px;
17 | padding-right: 10px;
18 | overflow-y: auto;
19 | display: block;
20 | padding-bottom: 30px;
21 | }
22 |
23 | .fade-in-bottom {
24 | position: relative;
25 | }
26 |
27 | .fade-in-bottom:after {
28 | content: '';
29 | position: absolute;
30 | z-index: 1;
31 | bottom: 0;
32 | pointer-events: none;
33 | background-image: linear-gradient(
34 | to bottom,
35 | rgba(255, 255, 255, 0),
36 | rgba(255, 255, 255, 1) 90%
37 | );
38 | width: 100%;
39 | height: 3em;
40 | }
41 |
42 | #empty-event-list {
43 | display: flex;
44 | height: 400px;
45 | align-items: center;
46 | }
47 |
48 | #more-events {
49 | width: 80%;
50 | }
51 |
52 | @media screen and (max-width: 991px) {
53 | #empty-event-list {
54 | justify-content: center;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/components/styles/Footer.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 |
3 | .footer {
4 | padding: 20px;
5 | text-align: center;
6 | color: white;
7 | }
8 |
9 | .link {
10 | color: white;
11 | }
12 |
13 | .theme {
14 | &-purple {
15 | background-color: $color-eng;
16 | a:hover {
17 | color: $color-math-light;
18 | }
19 | }
20 | &-pink {
21 | background-color: $color-math;
22 | a:hover {
23 | color: $color-eng;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/styles/Meetings.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 | .col-height {
3 | height: 400px;
4 | }
5 |
6 | .meeting-pdf {
7 | height: 100%;
8 | width: 100%;
9 | border-radius: 4px;
10 | border-color: lightgrey;
11 | border-style: solid;
12 | }
13 |
14 | .no-bottom-space {
15 | margin-bottom: 0;
16 | }
17 |
18 | .bold {
19 | font-weight: bold;
20 | }
21 |
22 | .colour {
23 | &-upcoming {
24 | color: $color-math;
25 | }
26 | &-previous {
27 | color: black;
28 | }
29 | }
30 |
31 | .archive-btn {
32 | float: right;
33 | background-color: lightgrey;
34 | border-width: 0px;
35 | margin-bottom: 3px;
36 | }
37 |
38 | .archive-btn:hover,
39 | .archive-btn:focus,
40 | .archive-btn:active {
41 | background-color: $color-math;
42 | color: white;
43 | }
44 |
45 | .archive-row {
46 | display: flex;
47 | align-items: center;
48 | }
49 |
--------------------------------------------------------------------------------
/src/components/styles/NavigationBar.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 |
3 | .navbar-nav a.nav-link.active:nth-child(odd) {
4 | color: $color-eng;
5 | }
6 |
7 | .navbar-nav a.nav-link.active:nth-child(even) {
8 | color: $color-math;
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/styles/NewsList.scss:
--------------------------------------------------------------------------------
1 | .news-list tr:nth-child(odd) .accent {
2 | color: var(--color-eng);
3 | }
4 |
5 | .news-list tr:nth-child(even) .accent {
6 | color: var(--color-math);
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/styles/ProfilePhotoGroup.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 | .society-profiles {
3 | margin-top: 30px;
4 | }
5 |
6 | @media screen and (min-width: 462px) {
7 | .card {
8 | font-size: calc(14px);
9 | line-height: calc(1.1em + 0.5vw);
10 | }
11 | }
12 |
13 | .card-img {
14 | max-height: 100% !important;
15 | }
16 |
17 | @media screen and (max-width: 461px) {
18 | .card {
19 | font-size: calc(9px + 0.25vw);
20 | line-height: calc(1.1em + 0.5vw);
21 | }
22 | }
23 |
24 | .card {
25 | padding-left: 15px;
26 | border-width: 0px;
27 | width: 100%;
28 | }
29 |
30 | .card-header {
31 | padding-top: 10px;
32 | padding-bottom: 10px;
33 | background-color: $color-eng;
34 | }
35 |
36 | .card-full-width {
37 | width: 100%;
38 | }
39 |
40 | .card-text {
41 | color: white;
42 | text-align: left;
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/styles/PromptActionButtons.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 |
3 | .action-grid {
4 | display: grid;
5 | grid-template-columns: auto min-content;
6 | grid-gap: 20px 10px;
7 | align-items: center;
8 | }
9 |
10 | .no-bottom-space {
11 | margin-bottom: 0;
12 | }
13 |
14 | .way-btn {
15 | float: right;
16 | background-color: $color-math;
17 | border-width: 0px;
18 | }
19 |
20 | .way-btn:hover {
21 | background-color: $color-math-light;
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/styles/ReactBigCalendar.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | @import 'styles/_colors';
3 | /* Component colors */
4 | $color-dates: $color-eng;
5 | $color-dates-invalid: $color-eng-light;
6 | $color-current-day: $color-eng-lightest;
7 | $color-event: $color-math;
8 | $color-event-selected: $color-math-light;
9 | $color-date-view-grid: $color-eng-light;
10 | $color-current-time: $color-math;
11 | span {
12 | font-weight: 300;
13 | }
14 |
15 | .rbc-btn {
16 | color: inherit;
17 | font: inherit;
18 | margin: 0;
19 | }
20 |
21 | button.rbc-btn {
22 | overflow: visible;
23 | text-transform: none;
24 | -webkit-appearance: button;
25 | cursor: pointer;
26 | }
27 |
28 | button[disabled].rbc-btn {
29 | cursor: not-allowed;
30 | }
31 |
32 | button.rbc-input::-moz-focus-inner {
33 | border: 0;
34 | padding: 0;
35 | }
36 |
37 | .rbc-calendar {
38 | box-sizing: border-box;
39 | height: 100%;
40 | display: flex;
41 | flex-direction: column;
42 | align-items: stretch;
43 | }
44 |
45 | .rbc-calendar *,
46 | .rbc-calendar *:before,
47 | .rbc-calendar *:after {
48 | box-sizing: inherit;
49 | }
50 |
51 | .rbc-abs-full,
52 | .rbc-row-bg {
53 | overflow: hidden;
54 | position: absolute;
55 | top: 0;
56 | left: 0;
57 | right: 0;
58 | bottom: 0;
59 | }
60 |
61 | .rbc-ellipsis,
62 | .rbc-event-label,
63 | .rbc-row-segment .rbc-event-content,
64 | .rbc-show-more {
65 | display: block;
66 | overflow: hidden;
67 | text-overflow: ellipsis;
68 | white-space: nowrap;
69 | }
70 |
71 | .rbc-rtl {
72 | direction: rtl;
73 | }
74 |
75 | .rbc-off-range {
76 | color: $color-dates-invalid;
77 | }
78 |
79 | .rbc-off-range-bg {
80 | background: #ffffff;
81 | }
82 |
83 | .rbc-header {
84 | overflow: hidden;
85 | flex: 1 0 0%;
86 | text-overflow: ellipsis;
87 | white-space: nowrap;
88 | padding: 0 3px;
89 | text-align: left;
90 | vertical-align: middle;
91 | font-weight: bold;
92 | font-size: 90%;
93 | min-height: 0;
94 | /* border-bottom: 1px solid #DDD; */
95 | margin-bottom: 5px;
96 | }
97 |
98 | .rbc-header + .rbc-header {
99 | /* border-left: 1px solid #DDD; */
100 | }
101 |
102 | .rbc-rtl .rbc-header + .rbc-header {
103 | border-left-width: 0;
104 | /* border-right: 1px solid #DDD; */
105 | }
106 |
107 | .rbc-header > a,
108 | .rbc-header > a:active,
109 | .rbc-header > a:visited {
110 | color: inherit;
111 | text-decoration: none;
112 | }
113 |
114 | .rbc-row-content {
115 | position: relative;
116 | user-select: none;
117 | -webkit-user-select: none;
118 | z-index: 4;
119 | }
120 |
121 | .rbc-today {
122 | background-color: $color-current-day;
123 | }
124 |
125 | .rbc-toolbar {
126 | display: flex;
127 | flex-wrap: wrap;
128 | justify-content: center;
129 | align-items: center;
130 | margin-bottom: 10px;
131 | font-size: 16px;
132 | }
133 |
134 | .rbc-toolbar .rbc-toolbar-label {
135 | flex-grow: 1;
136 | padding: 0 10px;
137 | text-align: center;
138 | }
139 |
140 | .rbc-toolbar button {
141 | padding: 0.375rem 1rem;
142 | margin-right: 5px;
143 | border-radius: 0px;
144 | line-height: normal;
145 | white-space: nowrap;
146 | color: #fff;
147 | background-color: #6c757d;
148 | border-color: #6c757d;
149 | user-select: none;
150 | border: 1px solid transparent;
151 | padding: 0.375rem 0.75rem;
152 | font-size: 1rem;
153 | line-height: 1.5;
154 | border-radius: 0.25rem;
155 | transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out,
156 | border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
157 | display: inline-block;
158 | font-weight: 400;
159 | text-align: center;
160 | white-space: nowrap;
161 | vertical-align: middle;
162 | }
163 |
164 | .rbc-toolbar button:active,
165 | .rbc-toolbar button.rbc-active {
166 | color: #fff;
167 | background-color: #6c757d;
168 | border-color: #6c757d;
169 | }
170 |
171 | .rbc-toolbar button:active:hover,
172 | .rbc-toolbar button:active:focus,
173 | .rbc-toolbar button.rbc-active:focus {
174 | color: #fff;
175 | background-color: #343a40;
176 | border-color: #343a40;
177 | }
178 |
179 | .rbc-toolbar button:focus {
180 | color: #fff;
181 | background-color: #343a40;
182 | border-color: #343a40;
183 | }
184 |
185 | .rbc-toolbar button:hover,
186 | .rbc-toolbar button.rbc-active:hover {
187 | color: #fff;
188 | background-color: #343a40;
189 | border-color: #343a40;
190 | }
191 |
192 | .rbc-btn-group {
193 | display: inline-block;
194 | white-space: nowrap;
195 | }
196 |
197 | .rbc-btn-group button + button {
198 | margin-left: -1px;
199 | }
200 |
201 | .rbc-rtl .rbc-btn-group button + button {
202 | margin-left: 0;
203 | margin-right: -1px;
204 | }
205 |
206 | .rbc-btn-group + .rbc-btn-group,
207 | .rbc-btn-group + button {
208 | margin-left: 10px;
209 | }
210 |
211 | .rbc-event {
212 | border: none;
213 | box-sizing: border-box;
214 | box-shadow: none;
215 | margin: 3px;
216 | padding: 2px 5px;
217 | background-color: $color-event;
218 | border-radius: 3px;
219 | color: #fff;
220 | cursor: pointer;
221 | width: 100%;
222 | text-align: left;
223 | font-size: 12px;
224 | }
225 |
226 | .rbc-slot-selecting .rbc-event {
227 | cursor: inherit;
228 | pointer-events: none;
229 | }
230 |
231 | .rbc-event.rbc-selected {
232 | background-color: $color-event-selected;
233 | }
234 |
235 | .rbc-event:focus {
236 | outline: 5px auto #3b99fc;
237 | }
238 |
239 | .rbc-event-label {
240 | font-size: 80%;
241 | }
242 |
243 | .rbc-event-overlaps {
244 | box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5);
245 | }
246 |
247 | .rbc-event-continues-prior {
248 | border-top-left-radius: 0;
249 | border-bottom-left-radius: 0;
250 | }
251 |
252 | .rbc-event-continues-after {
253 | border-top-right-radius: 0;
254 | border-bottom-right-radius: 0;
255 | }
256 |
257 | .rbc-event-continues-earlier {
258 | border-top-left-radius: 0;
259 | border-top-right-radius: 0;
260 | }
261 |
262 | .rbc-event-continues-later {
263 | border-bottom-left-radius: 0;
264 | border-bottom-right-radius: 0;
265 | }
266 |
267 | .rbc-row {
268 | display: flex;
269 | flex-direction: row;
270 | }
271 |
272 | .rbc-row-segment {
273 | padding: 0 1px 1px 1px;
274 | }
275 |
276 | .rbc-selected-cell {
277 | background-color: rgba(0, 0, 0, 0.1);
278 | }
279 |
280 | .rbc-show-more {
281 | background-color: rgba(255, 255, 255, 0.3);
282 | z-index: 4;
283 | font-weight: bold;
284 | font-size: 85%;
285 | height: auto;
286 | line-height: normal;
287 | }
288 |
289 | .rbc-month-view {
290 | position: relative;
291 | /* border: 1px solid #DDD; */
292 | display: flex;
293 | flex-direction: column;
294 | flex: 1 0 0;
295 | width: 100%;
296 | user-select: none;
297 | -webkit-user-select: none;
298 | height: 100%;
299 | }
300 |
301 | .rbc-month-header {
302 | display: flex;
303 | flex-direction: row;
304 | }
305 |
306 | .rbc-month-row {
307 | display: flex;
308 | position: relative;
309 | flex-direction: column;
310 | flex: 1 0 0;
311 | flex-basis: 0px;
312 | overflow: hidden;
313 | height: 100%;
314 | color: $color-dates;
315 | }
316 |
317 | .rbc-month-row + .rbc-month-row {
318 | /* border-top: 1px solid #DDD; */
319 | }
320 |
321 | .rbc-date-cell {
322 | flex: 1 1;
323 | min-width: 0;
324 | padding-left: 3px;
325 | text-align: left;
326 | font-weight: 300;
327 | }
328 |
329 | .rbc-date-cell.rbc-now {
330 | font-weight: bold;
331 | }
332 |
333 | .rbc-date-cell > a,
334 | .rbc-date-cell > a:active,
335 | .rbc-date-cell > a:visited {
336 | color: inherit;
337 | text-decoration: none;
338 | }
339 |
340 | .rbc-row-bg {
341 | display: flex;
342 | flex-direction: row;
343 | flex: 1 0;
344 | overflow: hidden;
345 | }
346 |
347 | .rbc-day-bg {
348 | flex: 1 0 0%;
349 | }
350 |
351 | .rbc-day-bg + .rbc-day-bg {
352 | /* border-left: 1px solid #DDD; */
353 | }
354 |
355 | .rbc-rtl .rbc-day-bg + .rbc-day-bg {
356 | border-left-width: 0;
357 | /* border-right: 1px solid #DDD; */
358 | }
359 |
360 | .rbc-overlay {
361 | position: absolute;
362 | z-index: 5;
363 | border: 1px solid #e5e5e5;
364 | background-color: #fff;
365 | box-shadow: 0 5px 15px rgba(0, 0, 0, 0.25);
366 | padding: 10px;
367 | }
368 |
369 | .rbc-overlay > * + * {
370 | margin-top: 1px;
371 | }
372 |
373 | .rbc-overlay-header {
374 | border-bottom: 1px solid #e5e5e5;
375 | margin: -10px -10px 5px -10px;
376 | padding: 2px 10px;
377 | }
378 |
379 | .rbc-agenda-view {
380 | display: flex;
381 | flex-direction: column;
382 | flex: 1 0 0;
383 | overflow: auto;
384 | }
385 |
386 | .rbc-agenda-view table.rbc-agenda-table {
387 | width: 100%;
388 | border: 1px solid #ddd;
389 | border-spacing: 0;
390 | border-collapse: collapse;
391 | }
392 |
393 | .rbc-agenda-view table.rbc-agenda-table tbody > tr > td {
394 | padding: 5px 10px;
395 | vertical-align: top;
396 | }
397 |
398 | .rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell {
399 | padding-left: 15px;
400 | padding-right: 15px;
401 | text-transform: lowercase;
402 | }
403 |
404 | .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
405 | border-left: 1px solid $color-date-view-grid;
406 | }
407 |
408 | .rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
409 | border-left-width: 0;
410 | border-right: 1px solid $color-date-view-grid;
411 | }
412 |
413 | .rbc-agenda-view table.rbc-agenda-table tbody > tr + tr {
414 | border-top: 1px solid $color-date-view-grid;
415 | }
416 |
417 | .rbc-agenda-view table.rbc-agenda-table thead > tr > th {
418 | padding: 3px 5px;
419 | text-align: left;
420 | border-bottom: 1px solid $color-date-view-grid;
421 | }
422 |
423 | .rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th {
424 | text-align: right;
425 | }
426 |
427 | .rbc-agenda-time-cell {
428 | text-transform: lowercase;
429 | }
430 |
431 | .rbc-agenda-time-cell .rbc-continues-after:after {
432 | content: ' »';
433 | }
434 |
435 | .rbc-agenda-time-cell .rbc-continues-prior:before {
436 | content: '« ';
437 | }
438 |
439 | .rbc-agenda-date-cell,
440 | .rbc-agenda-time-cell {
441 | white-space: nowrap;
442 | }
443 |
444 | .rbc-agenda-event-cell {
445 | width: 100%;
446 | }
447 |
448 | .rbc-time-column {
449 | display: flex;
450 | flex-direction: column;
451 | min-height: 100%;
452 | }
453 |
454 | .rbc-time-column .rbc-timeslot-group {
455 | flex: 1;
456 | }
457 |
458 | .rbc-timeslot-group {
459 | border-bottom: 1px solid $color-date-view-grid;
460 | min-height: 40px;
461 | display: flex;
462 | flex-flow: column nowrap;
463 | }
464 |
465 | .rbc-time-gutter,
466 | .rbc-header-gutter {
467 | flex: none;
468 | }
469 |
470 | .rbc-label {
471 | padding: 0 5px;
472 | }
473 |
474 | .rbc-day-slot {
475 | position: relative;
476 | }
477 |
478 | .rbc-day-slot .rbc-events-container {
479 | bottom: 0;
480 | left: 0;
481 | position: absolute;
482 | right: 0;
483 | margin-right: 10px;
484 | top: 0;
485 | }
486 |
487 | .rbc-day-slot .rbc-events-container.rbc-rtl {
488 | left: 10px;
489 | right: 0;
490 | }
491 |
492 | .rbc-day-slot .rbc-event {
493 | border: 0px solid $color-event;
494 | display: flex;
495 | max-height: 100%;
496 | min-height: 20px;
497 | flex-flow: column wrap;
498 | align-items: flex-start;
499 | overflow: hidden;
500 | position: absolute;
501 | }
502 |
503 | .rbc-day-slot .rbc-event-label {
504 | flex: none;
505 | padding-right: 5px;
506 | width: auto;
507 | }
508 |
509 | .rbc-day-slot .rbc-event-content {
510 | width: 100%;
511 | flex: 1 1 0;
512 | word-wrap: break-word;
513 | line-height: 1;
514 | height: 100%;
515 | min-height: 1em;
516 | }
517 |
518 | .rbc-day-slot .rbc-time-slot {
519 | border-top: 0px solid #f7f7f7;
520 | }
521 |
522 | .rbc-time-view-resources .rbc-time-gutter,
523 | .rbc-time-view-resources .rbc-time-header-gutter {
524 | position: sticky;
525 | left: 0;
526 | background-color: white;
527 | border-right: 1px solid $color-date-view-grid;
528 | z-index: 10;
529 | margin-right: -1px;
530 | }
531 |
532 | .rbc-time-view-resources .rbc-time-header {
533 | overflow: hidden;
534 | }
535 |
536 | .rbc-time-view-resources .rbc-time-header-content {
537 | min-width: auto;
538 | flex: 1 0 0;
539 | flex-basis: 0px;
540 | }
541 |
542 | .rbc-time-view-resources .rbc-time-header-cell-single-day {
543 | display: none;
544 | }
545 |
546 | .rbc-time-view-resources .rbc-day-slot {
547 | min-width: 140px;
548 | }
549 |
550 | .rbc-time-view-resources .rbc-header,
551 | .rbc-time-view-resources .rbc-day-bg {
552 | width: 140px;
553 | flex: 1 1 0;
554 | flex-basis: 0 px;
555 | }
556 |
557 | .rbc-time-header-content + .rbc-time-header-content {
558 | margin-left: -1px;
559 | }
560 |
561 | .rbc-time-slot {
562 | flex: 1 0 0;
563 | }
564 |
565 | .rbc-time-slot.rbc-now {
566 | font-weight: bold;
567 | }
568 |
569 | .rbc-day-header {
570 | text-align: center;
571 | }
572 |
573 | .rbc-slot-selection {
574 | z-index: 10;
575 | position: absolute;
576 | background-color: rgba(0, 0, 0, 0.5);
577 | color: white;
578 | font-size: 75%;
579 | width: 100%;
580 | padding: 3px;
581 | }
582 |
583 | .rbc-slot-selecting {
584 | cursor: move;
585 | }
586 |
587 | .rbc-time-view {
588 | display: flex;
589 | flex-direction: column;
590 | flex: 1;
591 | width: 100%;
592 | border: 0px solid #ddd;
593 | min-height: 0;
594 | }
595 |
596 | .rbc-time-view .rbc-time-gutter {
597 | white-space: nowrap;
598 | }
599 |
600 | .rbc-time-view .rbc-allday-cell {
601 | box-sizing: content-box;
602 | width: 100%;
603 | height: 100%;
604 | position: relative;
605 | }
606 |
607 | .rbc-time-view .rbc-allday-cell + .rbc-allday-cell {
608 | border-left: 1px solid #ddd;
609 | }
610 |
611 | .rbc-time-view .rbc-allday-events {
612 | position: relative;
613 | z-index: 4;
614 | }
615 |
616 | .rbc-time-view .rbc-row {
617 | box-sizing: border-box;
618 | min-height: 20px;
619 | }
620 |
621 | .rbc-time-header {
622 | display: flex;
623 | flex: 0 0 auto;
624 | flex-direction: row;
625 | }
626 |
627 | .rbc-time-header.rbc-overflowing {
628 | border-right: 0px solid #ddd;
629 | }
630 |
631 | .rbc-rtl .rbc-time-header.rbc-overflowing {
632 | border-right-width: 0;
633 | border-left: 1px solid #ddd;
634 | }
635 |
636 | .rbc-time-header > .rbc-row:first-child {
637 | border-bottom: 1px solid #ddd;
638 | }
639 |
640 | .rbc-time-header > .rbc-row.rbc-row-resource {
641 | border-bottom: 1px solid #ddd;
642 | }
643 |
644 | .rbc-time-header-cell-single-day {
645 | display: none;
646 | }
647 |
648 | .rbc-time-header-content {
649 | flex: 1;
650 | display: flex;
651 | min-width: 0;
652 | flex-direction: column;
653 | border-left: 1px solid $color-date-view-grid;
654 | }
655 |
656 | .rbc-rtl .rbc-time-header-content {
657 | border-left-width: 0;
658 | border-right: 1px solid $color-date-view-grid;
659 | }
660 |
661 | .rbc-time-header-content > .rbc-row.rbc-row-resource {
662 | border-bottom: 1px solid $color-date-view-grid;
663 | flex-shrink: 0;
664 | }
665 |
666 | .rbc-time-content {
667 | display: flex;
668 | flex: 1 0 0%;
669 | align-items: flex-start;
670 | width: 100%;
671 | border-top: 2px solid $color-date-view-grid;
672 | overflow-y: auto;
673 | position: relative;
674 | }
675 |
676 | .rbc-time-content > .rbc-time-gutter {
677 | flex: none;
678 | }
679 |
680 | .rbc-time-content > * + * > * {
681 | border-left: 1px solid $color-date-view-grid;
682 | }
683 |
684 | .rbc-rtl .rbc-time-content > * + * > * {
685 | border-left-width: 0;
686 | border-right: 1px solid $color-date-view-grid;
687 | }
688 |
689 | .rbc-time-content > .rbc-day-slot {
690 | width: 100%;
691 | user-select: none;
692 | -webkit-user-select: none;
693 | }
694 |
695 | .rbc-current-time-indicator {
696 | position: absolute;
697 | z-index: 3;
698 | left: 0;
699 | right: 0;
700 | height: 1px;
701 | background-color: $color-current-time;
702 | pointer-events: none;
703 | }
704 |
--------------------------------------------------------------------------------
/src/containers/About.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Container } from 'react-bootstrap'
3 | import ProfilePhotoGroup from 'components/ProfilePhotoGroup'
4 | import Footer from 'components/Footer'
5 | import url from 'url'
6 |
7 | const profileImage = (name) =>
8 | url.resolve(process.env.PUBLIC_URL, `/profiles/${name}.jpg`)
9 |
10 | class About extends Component {
11 | render() {
12 | return (
13 |
14 |
15 |
16 | What is SE Soc?
17 |
18 | Software Engineering Society (SE Soc) is a council that runs
19 | community initiatives within the SE program. Through class and
20 | program-wide events, such as game nights, online events, virtual
21 | dinners and coffee chats, we hope you get to meet all the other
22 | brilliant people in SE! We also run resume critiques and interview
23 | prep sessions, hosted by upper years, to help you get a better
24 | shot at the jobs you want. You can listen to a highlight of the
25 | cool stuff that everyone in SE is up to through our podcast,
26 | Sessions by SE.
27 |
28 |
29 | Meet The Team
30 |
31 | A-Soc represents the even years (SE2022, SE2024, SE2026) and
32 | B-Soc represents the odd years (SE2023, SE2025). We’re a
33 | friendly bunch, feel free to say hi if we ever bump into each
34 | other online or on campus!
35 |
36 |
67 |
92 |
93 |
94 |
95 |
96 |
97 | )
98 | }
99 | }
100 |
101 | export default About
102 |
--------------------------------------------------------------------------------
/src/containers/Blog.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Container } from 'react-bootstrap'
3 | import Moment from 'moment'
4 | import groupBy from 'lodash/groupBy'
5 | import map from 'lodash/map'
6 | import flow from 'lodash/flow'
7 | import partialRight from 'lodash/partialRight'
8 | import orderBy from 'lodash/orderBy'
9 |
10 | import Footer from 'components/Footer'
11 | import BlogPostsGroup from 'components/BlogPostsGroup'
12 | import { blogPosts } from 'content/BlogContent.js'
13 | import 'App.scss'
14 |
15 | const getDate = (date, dateFn = (date) => date) => {
16 | return dateFn(Moment.unix(date))
17 | }
18 |
19 | const formatPostsByDate = (blogPosts, dateFn, sortOrder) =>
20 | flow([
21 | partialRight(groupBy, (post) => getDate(post.date, dateFn)),
22 | partialRight(map, (posts, key) => [key, posts]),
23 | partialRight(orderBy, 0, sortOrder),
24 | ])(blogPosts)
25 |
26 | class Blog extends Component {
27 | renderBlogPosts(yearlyPosts) {
28 | const monthlyPosts = formatPostsByDate(
29 | yearlyPosts,
30 | // 1. The Moment library has the audacity to return months (& dates) zero-indexed (0=Jan, 11=Dec)
31 | // we don't need to worry about dates because we just sort with them (and never display them).
32 | (date) => date.month() + 1,
33 | 'desc',
34 | )
35 | return map(monthlyPosts, ([month, posts], index) => {
36 | const orderedPosts = orderBy(posts, 'date', 'desc')
37 | return (
38 |
44 | )
45 | })
46 | }
47 |
48 | renderMonthlyPosts() {
49 | const yearlyPosts = formatPostsByDate(
50 | blogPosts,
51 | (date) => date.year(),
52 | 'desc',
53 | )
54 | return map(yearlyPosts, ([year, posts]) => (
55 |
56 |
{year}
57 | {this.renderBlogPosts(posts)}
58 |
59 | ))
60 | }
61 |
62 | render() {
63 | return (
64 |
65 |
66 |
67 | Blog
68 | {this.renderMonthlyPosts()}
69 |
70 |
71 |
72 |
73 | )
74 | }
75 | }
76 |
77 | export default Blog
78 |
--------------------------------------------------------------------------------
/src/containers/Events.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import EventList from 'components/EventList'
3 | import EventCalendar from 'components/EventCalendar'
4 | import Footer from 'components/Footer'
5 | import { Container, Row, Col, Button } from 'react-bootstrap'
6 | import { getEvents, filterUpcomingEvents, CALENDARS } from 'modules/gcal'
7 | import 'App.scss'
8 | import 'containers/styles/Events.scss'
9 |
10 | const Events = () => {
11 | const [events, setEvents] = useState([])
12 |
13 | useEffect(() => {
14 | async function getAllEvents() {
15 | setEvents(await getEvents(CALENDARS.SESOC))
16 | }
17 | getAllEvents()
18 | }, [])
19 |
20 | return (
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
39 | + Google Calendar
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | )
49 | }
50 |
51 | export default Events
52 |
--------------------------------------------------------------------------------
/src/containers/GetInvolved.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Container, Row, Col } from 'react-bootstrap'
3 | import PromptActionButtons from 'components/PromptActionButtons'
4 | import Meetings from 'components/Meetings'
5 | import url from 'url'
6 | import Footer from 'components/Footer'
7 | import 'containers/styles/GetInvolved.scss'
8 |
9 | const getInvolved = url.resolve(
10 | process.env.PUBLIC_URL,
11 | '/illustrations/get-involved.png',
12 | )
13 |
14 | class GetInvolved extends Component {
15 | render() {
16 | return (
17 |
18 |
19 |
20 |
21 |
22 | Get Involved
23 |
42 |
43 |
44 |
49 |
50 |
51 |
52 |
53 | Meetings
54 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | )
83 | }
84 | }
85 |
86 | export default GetInvolved
87 |
--------------------------------------------------------------------------------
/src/containers/Home.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import { Container, Jumbotron, Row, Col } from 'react-bootstrap'
3 | import { Link } from 'react-router-dom'
4 | import url from 'url'
5 | import PropTypes from 'prop-types'
6 | import Footer from '../components/Footer'
7 | import { getEvents, CALENDARS, filterUpcomingEvents } from '../modules/gcal'
8 | import 'containers/styles/Home.scss'
9 |
10 | const heroImage = url.resolve(process.env.PUBLIC_URL, '/illustrations/hero.png')
11 |
12 | const eventCal = url.resolve(
13 | process.env.PUBLIC_URL,
14 | '/illustrations/calendar.png',
15 | )
16 |
17 | const coffeeChat = url.resolve(
18 | process.env.PUBLIC_URL,
19 | '/illustrations/coffee-chat.png',
20 | )
21 |
22 | const Hero = () => (
23 |
24 |
25 |
26 |
27 |
28 |
29 | Software Engineering Society brings the SE student community
30 | together.
31 |
32 |
33 |
34 |
35 |
36 | )
37 |
38 | const Content = (props) => {
39 | var upcomingEvent
40 | if (props.events[0]) {
41 | upcomingEvent = props.events[0]
42 | }
43 |
44 | return (
45 |
46 |
47 |
51 | {upcomingEvent ? (
52 | <>
53 | Missed us last time? Catch us at:
54 |
55 |
60 | {upcomingEvent.title}
61 |
62 | . Or, check out all upcoming events.
63 |
64 | >
65 | ) : (
66 | <>
67 | More events are coming soon!
68 |
69 | Check out all of our past events.
70 |
71 | >
72 | )}
73 |
74 |
75 |
80 |
81 |
82 |
83 |
84 |
94 |
95 |
99 |
104 |
105 |
106 |
107 | )
108 | }
109 |
110 | Content.propTypes = {
111 | events: PropTypes.arrayOf(PropTypes.object).isRequired,
112 | }
113 |
114 | const Home = () => {
115 | const [events, setEvents] = useState([])
116 |
117 | useEffect(() => {
118 | async function getAllEvents() {
119 | setEvents(await getEvents(CALENDARS.SESOC))
120 | }
121 | getAllEvents()
122 | }, [])
123 |
124 | return (
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | )
133 | }
134 |
135 | export default Home
136 |
--------------------------------------------------------------------------------
/src/containers/Sponsors.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import ComingSoon from 'components/ComingSoon'
3 |
4 | class Sponsors extends Component {
5 | render() {
6 | return
7 | }
8 | }
9 |
10 | export default Sponsors
11 |
--------------------------------------------------------------------------------
/src/containers/Wise.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { Container, Row, Col, Button, Accordion, Card } from 'react-bootstrap'
3 | import url from 'url'
4 | import PropTypes from 'prop-types'
5 | import Footer from 'components/Footer'
6 | import PromptActionButtons from 'components/PromptActionButtons'
7 | import EventCalendar from 'components/EventCalendar'
8 | import { getEvents, CALENDARS } from 'modules/gcal'
9 | import 'containers/styles/Wise.scss'
10 |
11 | const SLACK_LINK = 'https://join.slack.com/t/uw-wise/signup'
12 | const MAILING_LIST_LINK =
13 | 'https://lists.uwaterloo.ca/mailman/listinfo/women-in-se'
14 | const FACEBOOK_LINK = 'https://forms.gle/piWhPZ85zyRVCNa77'
15 | const FEEDBACK_FORM_LINK = 'https://forms.gle/rvzrQ7X4kStmKDYh9'
16 | const CALENDAR_LINK =
17 | 'https://calendar.google.com/calendar/b/7?cid=dXdhdGVybG9vd2lzZUBnbWFpbC5jb20'
18 |
19 | const girlsImage = url.resolve(
20 | process.env.PUBLIC_URL,
21 | '/illustrations/wise-girls.png',
22 | )
23 | const computerImage = url.resolve(
24 | process.env.PUBLIC_URL,
25 | '/illustrations/computer.png',
26 | )
27 | const wiseLogo = url.resolve(process.env.PUBLIC_URL, '/logos/wise-logo.png')
28 |
29 | // TODO: use ExternalLink component on rest of site
30 | const ExternalLink = ({ href, children, ...restProps }) => (
31 |
32 | {children}
33 |
34 | )
35 | ExternalLink.propTypes = {
36 | href: PropTypes.string.isRequired,
37 | children: PropTypes.node.isRequired,
38 | }
39 |
40 | const FAQS = [
41 | {
42 | question: 'Who does WiSE support?',
43 | answer: (
44 |
45 | WiSE recognizes women, as well as those whose gender identity is neither
46 | male nor female, including gender-fluid, non-binary, agender and more.
47 | WiSE advocates for representation of all genders in software
48 | engineering, and welcomes people with under-represented gender
49 | identities to all of our events. Additionally, some of WiSE’s events are
50 | open to all genders.
51 |
52 | ),
53 | },
54 | {
55 | question: 'What does “women-only” mean?',
56 | answer: (
57 |
58 | Our women only events are open to cis and trans women, and those whose
59 | gender identity is neither male nor female, including gender-fluid,
60 | non-binary, agender and more. We welcome people with under-represented
61 | gender identities to our women-only events.
62 |
63 | ),
64 | },
65 | {
66 | question: 'What events do you run each term?',
67 | answer: (
68 |
69 | Events vary from term to term, but in the past we have run a brunch,
70 | various mentoring activities, several casual board game nights, and a
71 | “How to get an awesome co-op” workshop. Check our our{' '}
72 | WiSE events calendar below for more
73 | information about our upcoming events!
74 |
75 | ),
76 | },
77 | {
78 | question: 'Why do you hold women-only events?',
79 | answer: (
80 |
81 |
82 | Currently, women and those with gender identities that are neither
83 | male nor female are under-represented in software engineering. Some
84 | women do not feel comfortable attending events where they know that
85 | the majority of attendants will be male. We hold women-only events to
86 | lessen this issue.
87 |
88 |
89 | Following in the footsteps of{' '}
90 | WiCS , we
91 | hold women-only technical events to reduce the feeling of{' '}
92 |
93 | letting the side down
94 |
95 | . These women-only opportunities allow women to participate without
96 | the fear or making mistakes that will be interpreted as evidence that
97 | women are inferior at computing.
98 |
99 |
100 | ),
101 | },
102 | {
103 | question: 'Where can I give my feedback about WiSE?',
104 | answer: (
105 |
106 | We love to hear feedback! You can give your feedback on our slack, or
107 | for an anonymous option - fill out our{' '}
108 | feedback form .
109 |
110 | ),
111 | },
112 | {
113 | question:
114 | 'Can you accommodate my food sensitivity at events where food is provided?',
115 | answer: (
116 |
117 | Yes! Please try to notify us at least a week in advance of the event.
118 |
119 | ),
120 | },
121 | {
122 | question: 'How can I get involved?',
123 | answer: (
124 |
125 | Join our slack! There you
126 | can chat with other WiSE, make event suggestions and volunteer to help
127 | run events. You can also attend our planning meeting that is held at the
128 | beginning of each term.
129 |
130 | ),
131 | },
132 | ]
133 |
134 | const Name = () => (
135 |
136 |
137 |
138 |
139 |
140 |
141 | Women in
142 |
143 | Software Engineering
144 |
145 |
146 |
147 | )
148 |
149 | const WhoWeAre = () => (
150 |
151 |
152 | Who We Are
153 |
154 | Women in Software Engineering (WiSE) is a student-run organization that
155 | exists to encourage, support and advocate for women and non-binary*
156 | individuals who are studying Software Engineering at the University of
157 | Waterloo.
158 |
159 |
160 | We strive to build an inclusive and diverse environment which supports
161 | women, non-binary, and minoritized individuals in Software Engineering.
162 | WiSE holds events each term to build a supportive community and provide
163 | a variety of resources to empower women in tech.
164 |
165 | *all gender identities are welcome and supported
166 |
167 |
173 | Join Our Slack
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 | )
182 |
183 | const Faqs = ({ faqs }) => {
184 | const defaultActiveKey = '0'
185 | const [activeFaq, setActiveFaq] = useState(defaultActiveKey)
186 | return (
187 | <>
188 | FAQ
189 |
190 | {faqs.map(({ question, answer }, index) => {
191 | const stringIndex = index.toString()
192 | const isActiveFaq = activeFaq === stringIndex
193 | return (
194 |
195 |
198 | setActiveFaq(stringIndex)}
203 | >
204 |
205 | {isActiveFaq ? (
206 |
207 | ) : (
208 |
209 | )}
210 | {question}
211 |
212 |
213 |
214 |
215 | {answer}
216 |
217 |
218 | )
219 | })}
220 |
221 | >
222 | )
223 | }
224 |
225 | Faqs.propTypes = {
226 | faqs: PropTypes.arrayOf(
227 | PropTypes.shape({
228 | question: PropTypes.string.isRequired,
229 | answer: PropTypes.node.isRequired,
230 | }),
231 | ).isRequired,
232 | }
233 |
234 | const WiseEvents = ({ events }) => (
235 |
236 |
Events
237 |
238 |
239 |
240 |
241 |
247 | + WiSE Google Calendar
248 |
249 |
250 |
251 | )
252 |
253 | WiseEvents.propTypes = {
254 | events: PropTypes.arrayOf(PropTypes.object).isRequired,
255 | }
256 |
257 | const Resources = () => (
258 | <>
259 | Resources
260 |
261 | For more information on events or scholarship opportunities please
262 | checkout our{' '}
263 |
269 | resource hub
270 |
271 | .
272 |
273 | >
274 | )
275 |
276 | const GetInvolved = () => (
277 |
278 |
Get Involved
279 |
304 |
305 | )
306 |
307 | const ImageSection = ({ children }) => (
308 |
309 |
310 | {children}
311 |
312 |
317 |
322 |
323 |
324 | )
325 |
326 | const Videos = () => (
327 | <>
328 | Videos
329 | WiSE Upper Year Panel: Fall 2020
330 |
331 |
339 |
340 | >
341 | )
342 |
343 | ImageSection.propTypes = { children: PropTypes.node.isRequired }
344 |
345 | const Wise = () => {
346 | const [events, setEvents] = useState([])
347 |
348 | useEffect(() => {
349 | async function getAllEvents() {
350 | setEvents(await getEvents(CALENDARS.WISE))
351 | }
352 | getAllEvents()
353 | }, [])
354 |
355 | return (
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 | )
373 | }
374 |
375 | export default Wise
376 |
--------------------------------------------------------------------------------
/src/containers/styles/Events.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 | .cal {
3 | height: 600px;
4 | }
5 |
6 | .cal-add-btn {
7 | float: right;
8 | background-color: $color-eng;
9 | border-width: 0px;
10 | margin-bottom: 3px;
11 | }
12 |
13 | .cal-add-btn:hover {
14 | background-color: $color-eng-light;
15 | }
16 |
17 | @media (max-width: 992px) {
18 | }
19 |
--------------------------------------------------------------------------------
/src/containers/styles/GetInvolved.scss:
--------------------------------------------------------------------------------
1 | .image-get-involved-container {
2 | display: flex;
3 | justify-content: center;
4 | align-items: center;
5 | }
6 |
7 | @media screen and (max-width: 559px) {
8 | .image-get-involved {
9 | max-width: 100%;
10 | }
11 | }
12 |
13 | @media screen and (min-width: 560px) {
14 | .image-get-involved {
15 | max-width: 75%;
16 | }
17 | }
--------------------------------------------------------------------------------
/src/containers/styles/Home.scss:
--------------------------------------------------------------------------------
1 | /* Home Page Hero */
2 |
3 | #hero {
4 | background-color: #f0edf1;
5 | position: relative;
6 | overflow: hidden;
7 | padding-top: 0px;
8 | padding-bottom: 0px;
9 | display: flex;
10 | justify-content: center;
11 | }
12 |
13 | #hero-image {
14 | overflow-x: hidden;
15 | position: absolute;
16 | top: 0;
17 | z-index: 0;
18 | margin-left: 150px;
19 | top: 5px;
20 | }
21 |
22 | #intro {
23 | position: relative;
24 | z-index: 1;
25 | }
26 |
27 | /* Set a fixed size for screen sizes with width greater than 1400px */
28 | @media screen and (min-width: 1400px) {
29 | #hero {
30 | height: 480px;
31 | }
32 | #hero-image {
33 | width: 1010px;
34 | }
35 | #intro {
36 | padding-top: 70px;
37 | }
38 | #intro-text {
39 | font-size: 33.5px;
40 | }
41 | }
42 |
43 | /* Configure for tablet and desktop screen sizes */
44 | @media screen and (min-width: 576px) and (max-width: 1399px) {
45 | #hero {
46 | height: calc(200px + 20vw);
47 | }
48 | #hero-image {
49 | width: calc(450px + 40vw);
50 | }
51 | #intro {
52 | padding-top: 5%;
53 | }
54 | #intro-text {
55 | font-size: calc(16px + 1.25vw);
56 | }
57 | }
58 |
59 | /* Configure for mobile screen sizes */
60 | @media screen and (max-width: 576px) {
61 | #hero {
62 | height: 300px;
63 | }
64 | #hero-image {
65 | width: calc(100px + 100vw);
66 | opacity: 0.5;
67 | right: -20%;
68 | top: calc(80px - 12vw);
69 | }
70 | #intro {
71 | padding-top: 10%;
72 | }
73 | #intro-text {
74 | font-size: 28px;
75 | }
76 | }
77 |
78 | /* Home Page Content */
79 |
80 | .blurb-image-container {
81 | display: flex;
82 | justify-content: center;
83 | align-items: center;
84 | }
85 |
86 | .blurb-image-cal {
87 | max-width: 75%;
88 | }
89 |
90 | .blurb-image-coffee {
91 | max-width: 90%;
92 | }
93 |
94 | .blurb-content {
95 | margin-top: auto;
96 | margin-bottom: auto;
97 | }
98 |
99 | @media screen and (max-width: 576px) {
100 | .blurb-image-container {
101 | display: table-cell;
102 | vertical-align: middle;
103 | text-align: center;
104 | }
105 | .blurb-image-cal {
106 | max-width: 65%;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/containers/styles/Wise.scss:
--------------------------------------------------------------------------------
1 | @import 'styles/_colors';
2 |
3 | .wise-logo {
4 | max-height: 90px;
5 | float: right;
6 | }
7 |
8 | .girls-img,
9 | .computer-img {
10 | width: 100%;
11 | height: auto;
12 | }
13 |
14 | .slack-btn {
15 | background-color: $color-eng;
16 | border-width: 0px;
17 | }
18 |
19 | .cal {
20 | height: 500px;
21 | }
22 |
23 | .cal-add-btn {
24 | float: right;
25 | background-color: $color-eng;
26 | border-width: 0px;
27 | margin-bottom: 3px;
28 | }
29 |
30 | .cal-add-btn:hover,
31 | .slack-btn:hover {
32 | background-color: $color-eng-light;
33 | }
34 |
35 | .wise-accordian {
36 | & > :first-child {
37 | border-width: 1px;
38 | }
39 | }
40 |
41 | .wise-card {
42 | width: 100%;
43 | margin: 0;
44 | padding: 0;
45 | border-width: 0 1px 1px;
46 | border-color: #e8e8e8;
47 | border-style: solid;
48 | border-radius: 0;
49 | }
50 |
51 | .card-body {
52 | padding: 0;
53 | margin: 1.25rem;
54 | background-color: white;
55 |
56 | a {
57 | display: inline-block;
58 | }
59 |
60 | p {
61 | margin: 0;
62 | }
63 | }
64 |
65 | .wise-card-header {
66 | transition: background-color 0.15s ease-in-out;
67 | background-color: white;
68 | border-radius: 0 !important;
69 | border: none;
70 |
71 | .btn-link {
72 | color: black;
73 | font-size: 18px;
74 | &:hover,
75 | &:focus {
76 | text-decoration: none !important;
77 | }
78 | }
79 |
80 | button {
81 | width: 100%;
82 | text-align: left;
83 | }
84 | }
85 |
86 | .wise-card-header.active {
87 | background-color: $color-math;
88 |
89 | .btn-link {
90 | color: white;
91 | }
92 | }
93 |
94 | .faq-question {
95 | white-space: normal;
96 | }
97 |
98 | @media screen and (max-width: 991px) {
99 | .computer-img {
100 | max-height: 450px;
101 | width: auto;
102 | }
103 |
104 | .wise-get-involved {
105 | .action-grid {
106 | grid-template-columns: 1fr;
107 |
108 | p {
109 | display: none;
110 | }
111 | }
112 | }
113 | }
114 |
115 | /* from: https://www.benmarshall.me/responsive-iframes/ */
116 | .video-div {
117 | position: relative;
118 | padding-top: 66.66%;
119 | overflow: hidden;
120 |
121 | iframe {
122 | position: absolute;
123 | left: 0;
124 | top: 0;
125 | height: 100%;
126 | width: 100%;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/content/BlogContent.js:
--------------------------------------------------------------------------------
1 | const BLOG_TYPES = {
2 | PODCAST: 'Podcast',
3 | BLOG: 'Blog',
4 | NEWS: 'News',
5 | VIDEO: 'Video',
6 | }
7 |
8 | const BLOG_ICONS_MAP = new Map([
9 | [BLOG_TYPES.PODCAST, 'podcast.png'],
10 | [BLOG_TYPES.BLOG, 'default.png'],
11 | [BLOG_TYPES.NEWS, 'default.png'],
12 | [BLOG_TYPES.VIDEO, 'video.png'],
13 | ])
14 |
15 | const podcastRSSLink = {
16 | type: 'rss',
17 | link: 'https://anchor.fm/s/1ca1c6a8/podcast/rss',
18 | }
19 |
20 | const blogPosts = [
21 | {
22 | type: BLOG_TYPES.PODCAST,
23 | title: 'SXSE S01E01 - Running a Startup as an SE Student',
24 | date: '1586908800',
25 | links: [
26 | {
27 | type: 'spotify',
28 | link:
29 | 'https://open.spotify.com/episode/2AW4wE0Oygu4kWUYHIw0jO?si=KGnGYGoYS6CYXXYAMUJrfA',
30 | },
31 | {
32 | type: 'anchor',
33 | link:
34 | 'https://anchor.fm/sesoc/episodes/Running-a-Startup-as-an-SE-Student-ecr190/a-a1uoim4',
35 | },
36 | {
37 | type: 'apple',
38 | link:
39 | 'https://podcasts.apple.com/us/podcast/running-a-startup-as-an-se-student/id1508757308?i=1000471887899',
40 | },
41 | podcastRSSLink,
42 | ],
43 | },
44 | {
45 | type: BLOG_TYPES.PODCAST,
46 | title: 'SXSE S01E02 - SE FYDP: Team Mask',
47 | date: '1587945600',
48 | links: [
49 | {
50 | type: 'spotify',
51 | link:
52 | 'https://open.spotify.com/episode/24aGh1lNgFf8UPzdGGse5h?si=xi9XMkbPSmOt9rIUi-J5Ng',
53 | },
54 | {
55 | type: 'anchor',
56 | link:
57 | 'https://anchor.fm/sesoc/episodes/SE-FYDP-Team-Mask-edaguu/a-a21rlp2',
58 | },
59 | {
60 | type: 'apple',
61 | link:
62 | 'https://podcasts.apple.com/us/podcast/se-fydp-team-mask/id1508757308?i=1000472800670',
63 | },
64 | podcastRSSLink,
65 | ],
66 | },
67 | {
68 | type: BLOG_TYPES.PODCAST,
69 | title: 'SXSE S01E03 - How To Make The Most Out Of Your First Co-op',
70 | date: '1593561600',
71 | links: [
72 | {
73 | type: 'spotify',
74 | link:
75 | 'https://open.spotify.com/episode/6dSt5jaAgEtxvUew7YXz48?si=uArETrrJSlW1J5YjynUu7Q',
76 | },
77 | {
78 | type: 'anchor',
79 | link:
80 | 'https://anchor.fm/sesoc/episodes/How-to-Make-the-Most-out-of-Your-First-Co-op-eg5hd4/a-a2jl1iq',
81 | },
82 | {
83 | type: 'apple',
84 | link:
85 | 'https://podcasts.apple.com/us/podcast/how-to-make-the-most-out-of-your-first-co-op/id1508757308?i=1000480893251',
86 | },
87 | podcastRSSLink,
88 | ],
89 | },
90 | {
91 | type: BLOG_TYPES.PODCAST,
92 | title: "SXSE S01E04 - An SE Student's Guide to Extracurriculars",
93 | date: '1596931200',
94 | links: [
95 | {
96 | type: 'spotify',
97 | link: 'https://open.spotify.com/episode/4gHp1pky25xFfYdl7SlnTV',
98 | },
99 | {
100 | type: 'anchor',
101 | link:
102 | 'https://anchor.fm/sesoc/episodes/An-SE-Students-Guide-to-Extracurriculars-ehtc1v',
103 | },
104 | {
105 | type: 'apple',
106 | link:
107 | 'https://podcasts.apple.com/us/podcast/an-se-students-guide-to-extracurriculars/id1508757308?i=1000487614833',
108 | },
109 | podcastRSSLink,
110 | ],
111 | },
112 | {
113 | type: BLOG_TYPES.PODCAST,
114 | title:
115 | 'SXSE S01E05 - The Wild Adventure of First-Year Software Engineering',
116 | date: '1598659200',
117 | links: [
118 | {
119 | type: 'spotify',
120 | link: 'https://open.spotify.com/episode/0uB0ULL9OC5mFSsy7oOGh5',
121 | },
122 | {
123 | type: 'anchor',
124 | link:
125 | 'https://anchor.fm/sesoc/episodes/The-Wild-Adventure-of-First-Year-Software-Engineering-eir3ar',
126 | },
127 | {
128 | type: 'apple',
129 | link:
130 | 'https://podcasts.apple.com/us/podcast/the-wild-adventure-of-first-year-software-engineering/id1508757308?i=1000489507047',
131 | },
132 | podcastRSSLink,
133 | ],
134 | },
135 | {
136 | type: BLOG_TYPES.BLOG,
137 | title: 'Useful Links for Waterloo Software Engineering Students',
138 | date: '1600574400',
139 | links: [
140 | {
141 | type: 'default',
142 | link: 'https://github.com/Dhvani35729/UWaterloo-Links-SE',
143 | },
144 | ],
145 | },
146 | {
147 | type: BLOG_TYPES.VIDEO,
148 | title: 'Technical Interview Prep Workshop',
149 | date: '1600747200',
150 | links: [
151 | {
152 | type: 'default',
153 | link: 'https://youtu.be/Oyf7P1_7MHM',
154 | },
155 | ],
156 | },
157 | ]
158 |
159 | const recentBlogPost = blogPosts.reduce((prev, curr) =>
160 | Number(prev.date) > Number(curr.age) ? prev : curr,
161 | )
162 |
163 | export { BLOG_TYPES, BLOG_ICONS_MAP, blogPosts, recentBlogPost }
164 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | import React from 'react'
3 | import ReactDOM from 'react-dom'
4 | import './index.css'
5 | import App from './App'
6 | import * as serviceWorker from './serviceWorker'
7 | import { BrowserRouter } from 'react-router-dom'
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root'),
13 | )
14 |
15 | // If you want your app to work offline and load faster, you can change
16 | // unregister() to register() below. Note this comes with some pitfalls.
17 | // Learn more about service workers: http://bit.ly/CRA-PWA
18 | serviceWorker.unregister()
19 |
--------------------------------------------------------------------------------
/src/modules/gcal.js:
--------------------------------------------------------------------------------
1 | import Axios from 'axios'
2 | import Moment from 'moment'
3 |
4 | export const CALENDARS = {
5 | SESOC: {
6 | CALENDAR_ID: process.env.REACT_APP_GOOGLE_CALENDAR_ID,
7 | API_KEY: process.env.REACT_APP_GOOGLE_CALENDAR_API_KEY,
8 | },
9 | WISE: {
10 | CALENDAR_ID: process.env.REACT_APP_GOOGLE_CALENDAR_ID_WISE,
11 | API_KEY: process.env.REACT_APP_GOOGLE_CALENDAR_API_KEY_WISE,
12 | },
13 | }
14 |
15 | const buildUrl = (CALENDAR_ID, API_KEY) =>
16 | `https://www.googleapis.com/calendar/v3/calendars/${CALENDAR_ID}/events?key=${API_KEY}`
17 |
18 | export async function getEvents(calendarType) {
19 | const { CALENDAR_ID, API_KEY } = calendarType
20 | const url = buildUrl(CALENDAR_ID, API_KEY)
21 |
22 | const events = []
23 | const response = await Axios.get(url)
24 | response.data.items.forEach((event) => {
25 | events.push({
26 | start: event.start.date || event.start.dateTime,
27 | end: event.end.date || event.end.dateTime,
28 | dateLabel: Moment(event.start.date || event.start.dateTime).format(
29 | 'MMMM Do, YYYY',
30 | ),
31 | title: event.summary,
32 | description: event.description,
33 | link: event.htmlLink,
34 | })
35 | })
36 | events.sort((e1, e2) => {
37 | var d1 = new Date(e1.start),
38 | d2 = new Date(e2.start)
39 | return d1 - d2
40 | })
41 |
42 | return events
43 | }
44 |
45 | export function filterUpcomingEvents(events) {
46 | let curDateTime = Moment()
47 | return events.filter((e) => Moment(e.end).isAfter(curDateTime))
48 | }
49 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | /* eslint-disable no-undef */
3 | // This optional code is used to register a service worker.
4 | // register() is not called by default.
5 |
6 | // This lets the app load faster on subsequent visits in production, and gives
7 | // it offline capabilities. However, it also means that developers (and users)
8 | // will only see deployed updates on subsequent visits to a page, after all the
9 | // existing tabs open on the page have been closed, since previously cached
10 | // resources are updated in the background.
11 |
12 | // To learn more about the benefits of this model and instructions on how to
13 | // opt-in, read http://bit.ly/CRA-PWA.
14 |
15 | const isLocalhost = Boolean(
16 | window.location.hostname === 'localhost' ||
17 | // [::1] is the IPv6 localhost address.
18 | window.location.hostname === '[::1]' ||
19 | // 127.0.0.1/8 is considered localhost for IPv4.
20 | window.location.hostname.match(
21 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
22 | ),
23 | )
24 |
25 | export function register(config) {
26 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
27 | // The URL constructor is available in all browsers that support SW.
28 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location)
29 | if (publicUrl.origin !== window.location.origin) {
30 | // Our service worker won't work if PUBLIC_URL is on a different origin
31 | // from what our page is served on. This might happen if a CDN is used to
32 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
33 | return
34 | }
35 |
36 | window.addEventListener('load', () => {
37 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
38 |
39 | if (isLocalhost) {
40 | // This is running on localhost. Let's check if a service worker still exists or not.
41 | checkValidServiceWorker(swUrl, config)
42 |
43 | // Add some additional logging to localhost, pointing developers to the
44 | // service worker/PWA documentation.
45 | navigator.serviceWorker.ready.then(() => {
46 | console.log(
47 | 'This web app is being served cache-first by a service ' +
48 | 'worker. To learn more, visit http://bit.ly/CRA-PWA',
49 | )
50 | })
51 | } else {
52 | // Is not localhost. Just register service worker
53 | registerValidSW(swUrl, config)
54 | }
55 | })
56 | }
57 | }
58 |
59 | function registerValidSW(swUrl, config) {
60 | navigator.serviceWorker
61 | .register(swUrl)
62 | .then((registration) => {
63 | registration.onupdatefound = () => {
64 | const installingWorker = registration.installing
65 | installingWorker.onstatechange = () => {
66 | if (installingWorker.state === 'installed') {
67 | if (navigator.serviceWorker.controller) {
68 | // At this point, the updated precached content has been fetched,
69 | // but the previous service worker will still serve the older
70 | // content until all client tabs are closed.
71 | console.log(
72 | 'New content is available and will be used when all ' +
73 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.',
74 | )
75 |
76 | // Execute callback
77 | if (config && config.onUpdate) {
78 | config.onUpdate(registration)
79 | }
80 | } else {
81 | // At this point, everything has been precached.
82 | // It's the perfect time to display a
83 | // "Content is cached for offline use." message.
84 | console.log('Content is cached for offline use.')
85 |
86 | // Execute callback
87 | if (config && config.onSuccess) {
88 | config.onSuccess(registration)
89 | }
90 | }
91 | }
92 | }
93 | }
94 | })
95 | .catch((error) => {
96 | console.error('Error during service worker registration:', error)
97 | })
98 | }
99 |
100 | function checkValidServiceWorker(swUrl, config) {
101 | // Check if the service worker can be found. If it can't reload the page.
102 | fetch(swUrl)
103 | .then((response) => {
104 | // Ensure service worker exists, and that we really are getting a JS file.
105 | if (
106 | response.status === 404 ||
107 | response.headers.get('content-type').indexOf('javascript') === -1
108 | ) {
109 | // No service worker found. Probably a different app. Reload the page.
110 | navigator.serviceWorker.ready.then((registration) => {
111 | registration.unregister().then(() => {
112 | window.location.reload()
113 | })
114 | })
115 | } else {
116 | // Service worker found. Proceed as normal.
117 | registerValidSW(swUrl, config)
118 | }
119 | })
120 | .catch(() => {
121 | console.log(
122 | 'No internet connection found. App is running in offline mode.',
123 | )
124 | })
125 | }
126 |
127 | export function unregister() {
128 | if ('serviceWorker' in navigator) {
129 | navigator.serviceWorker.ready.then((registration) => {
130 | registration.unregister()
131 | })
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/styles/_colors.scss:
--------------------------------------------------------------------------------
1 | $color-primary: black;
2 | $color-eng: #7e4b98;
3 | $color-eng-light: #a481b6;
4 | $color-eng-lightest: #cbb7d5;
5 | $color-math: #dd6faf;
6 | $color-math-light: #e38bbf;
7 |
--------------------------------------------------------------------------------