Merge branch 'master' of https://github.com/gjcampbell777/personal_site
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
name: Optimize images
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main, master ]
|
||||||
|
paths:
|
||||||
|
- 'src/assets/**'
|
||||||
|
- 'assets/**'
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'src/assets/**'
|
||||||
|
- 'assets/**'
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
optimize:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '18'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Run image optimizer
|
||||||
|
run: npm run optimize-images
|
||||||
|
|
||||||
|
- name: Upload optimized images
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: optimized-images
|
||||||
|
path: public/images
|
||||||
@@ -21,3 +21,8 @@
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
|
# amplify
|
||||||
|
.amplify
|
||||||
|
amplify_outputs*
|
||||||
|
amplifyconfiguration*
|
||||||
|
|||||||
@@ -1,6 +1,39 @@
|
|||||||
|
# personal_site
|
||||||
|
|
||||||
|
This repository is a React-based personal website for Gregory Campbell.
|
||||||
|
|
||||||
|
Quick commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# install deps (use legacy peer deps if you hit TypeScript/react-scripts conflicts)
|
||||||
|
npm install --legacy-peer-deps
|
||||||
|
|
||||||
|
# run dev server
|
||||||
|
npm start
|
||||||
|
|
||||||
|
# build production
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# optimize images (requires sharp)
|
||||||
|
# install sharp (one-time):
|
||||||
|
npm run optimize-images:install
|
||||||
|
# then run optimization:
|
||||||
|
npm run optimize-images
|
||||||
|
```
|
||||||
|
|
||||||
|
Image optimization
|
||||||
|
|
||||||
|
This repo includes `scripts/optimize-images.js`, a small Node script that uses `sharp` to generate WebP resized variants for images found in `src/assets`. The script writes outputs to `public/images` by default.
|
||||||
|
|
||||||
|
If you prefer a different pipeline, consider using `imagemin` or a CI-integrated image optimization step.
|
||||||
|
|
||||||
|
Deployment / Amplify notes
|
||||||
|
|
||||||
|
- The project uses `package-lock.json` (npm) — ensure CI is configured to use `npm install` and not `yarn`.
|
||||||
|
- If deploying via AWS Amplify and it errors with multiple lockfiles, ensure only one lockfile (package-lock.json) is present.
|
||||||
[](https://app.netlify.com/projects/gregoryjcampbell/deploys)
|
[](https://app.netlify.com/projects/gregoryjcampbell/deploys)
|
||||||
|
|
||||||
This is the source code for my [Personal Website](https://gregoryjcampbell.com).
|
This is the source code for my [Personal Website](https://gregoryjcampbell.netlify.app/).
|
||||||
|
|
||||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||||
|
|
||||||
|
|||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
version: 1
|
||||||
|
applications:
|
||||||
|
- frontend:
|
||||||
|
phases:
|
||||||
|
preBuild:
|
||||||
|
commands:
|
||||||
|
- npm install --legacy-peer-deps
|
||||||
|
build:
|
||||||
|
commands:
|
||||||
|
- npm run build
|
||||||
|
artifacts:
|
||||||
|
baseDirectory: build
|
||||||
|
files:
|
||||||
|
- "**/*"
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- node_modules/**/
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { defineAuth } from '@aws-amplify/backend';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define and configure your auth resource
|
||||||
|
* @see https://docs.amplify.aws/gen2/build-a-backend/auth
|
||||||
|
*/
|
||||||
|
export const auth = defineAuth({
|
||||||
|
loginWith: {
|
||||||
|
email: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { defineBackend } from '@aws-amplify/backend';
|
||||||
|
import { auth } from './auth/resource';
|
||||||
|
import { data } from './data/resource';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://docs.amplify.aws/react/build-a-backend/ to add storage, functions, and more
|
||||||
|
*/
|
||||||
|
defineBackend({
|
||||||
|
auth,
|
||||||
|
data,
|
||||||
|
});
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
|
||||||
|
|
||||||
|
/*== STEP 1 ===============================================================
|
||||||
|
The section below creates a Todo database table with a "content" field. Try
|
||||||
|
adding a new "isDone" field as a boolean. The authorization rule below
|
||||||
|
specifies that any unauthenticated user can "create", "read", "update",
|
||||||
|
and "delete" any "Todo" records.
|
||||||
|
=========================================================================*/
|
||||||
|
const schema = a.schema({
|
||||||
|
Todo: a
|
||||||
|
.model({
|
||||||
|
content: a.string(),
|
||||||
|
})
|
||||||
|
.authorization((allow) => [allow.guest()]),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Schema = ClientSchema<typeof schema>;
|
||||||
|
|
||||||
|
export const data = defineData({
|
||||||
|
schema,
|
||||||
|
authorizationModes: {
|
||||||
|
defaultAuthorizationMode: 'identityPool',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/*== STEP 2 ===============================================================
|
||||||
|
Go to your frontend source code. From your client-side code, generate a
|
||||||
|
Data client to make CRUDL requests to your table. (THIS SNIPPET WILL ONLY
|
||||||
|
WORK IN THE FRONTEND CODE FILE.)
|
||||||
|
|
||||||
|
Using JavaScript or Next.js React Server Components, Middleware, Server
|
||||||
|
Actions or Pages Router? Review how to generate Data clients for those use
|
||||||
|
cases: https://docs.amplify.aws/gen2/build-a-backend/data/connect-to-API/
|
||||||
|
=========================================================================*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
"use client"
|
||||||
|
import { generateClient } from "aws-amplify/data";
|
||||||
|
import type { Schema } from "@/amplify/data/resource";
|
||||||
|
|
||||||
|
const client = generateClient<Schema>() // use this Data client for CRUDL requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*== STEP 3 ===============================================================
|
||||||
|
Fetch records from the database and use them in your frontend component.
|
||||||
|
(THIS SNIPPET WILL ONLY WORK IN THE FRONTEND CODE FILE.)
|
||||||
|
=========================================================================*/
|
||||||
|
|
||||||
|
/* For example, in a React component, you can use this snippet in your
|
||||||
|
function's RETURN statement */
|
||||||
|
// const { data: todos } = await client.models.Todo.list()
|
||||||
|
|
||||||
|
// return <ul>{todos.map(todo => <li key={todo.id}>{todo.content}</li>)}</ul>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"type": "module"
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2022",
|
||||||
|
"module": "es2022",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"paths": {
|
||||||
|
"$amplify/*": [
|
||||||
|
"../.amplify/generated/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+31752
-1475
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,13 @@
|
|||||||
"repository": "https://github.com/gjcampbell777/personal_site.git",
|
"repository": "https://github.com/gjcampbell777/personal_site.git",
|
||||||
"author": "Gregory Campbell <gjcampbell777@gmail.com>",
|
"author": "Gregory Campbell <gjcampbell777@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"homepage": ".",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@testing-library/jest-dom": "^5.11.1",
|
"@testing-library/jest-dom": "^5.11.1",
|
||||||
"@testing-library/react": "^11.2.5",
|
"@testing-library/react": "^11.2.5",
|
||||||
"@testing-library/user-event": "^12.0.11",
|
"@testing-library/user-event": "^12.0.11",
|
||||||
|
"ajv": "^8.12.0",
|
||||||
|
"aws-amplify": "^6.17.0",
|
||||||
"bootstrap": "^5.0.0",
|
"bootstrap": "^5.0.0",
|
||||||
"immer": "9.0.6",
|
"immer": "9.0.6",
|
||||||
"ini": "2.0.0",
|
"ini": "2.0.0",
|
||||||
@@ -18,6 +21,8 @@
|
|||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-bootstrap": "^1.2.2",
|
"react-bootstrap": "^1.2.2",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
|
"react-helmet-async": "^1.3.0",
|
||||||
|
"react-is": "^19.2.7",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"styled-components": "^5.1.1"
|
"styled-components": "^5.1.1"
|
||||||
@@ -42,5 +47,15 @@
|
|||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@aws-amplify/backend": "^1.23.0",
|
||||||
|
"@aws-amplify/backend-cli": "^1.8.3",
|
||||||
|
"aws-cdk-lib": "^2.244.0",
|
||||||
|
"constructs": "^10.6.0",
|
||||||
|
"esbuild": "^0.28.0",
|
||||||
|
"sharp": "^0.34.5",
|
||||||
|
"tsx": "^4.22.4",
|
||||||
|
"typescript": "^4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-12
@@ -2,34 +2,25 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="The Personal Website of Gregory Campbell"
|
content="The Personal Website of Gregory Campbell"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="logo192.png" />
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
-->
|
-->
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="manifest.json" />
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
|
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
|
||||||
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
|
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
/>
|
/>
|
||||||
<!--
|
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
|
||||||
-->
|
|
||||||
<title>Gregory J Campbell</title>
|
<title>Gregory J Campbell</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"skills": {
|
||||||
|
"cavecrew": {
|
||||||
|
"source": "JuliusBrussee/caveman",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/cavecrew/SKILL.md",
|
||||||
|
"computedHash": "505d836228d1c5e14834ff5d62aad72390c7d27f79c6aa7f9a7a55ed6606d6a2"
|
||||||
|
},
|
||||||
|
"caveman": {
|
||||||
|
"source": "JuliusBrussee/caveman",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/caveman/SKILL.md",
|
||||||
|
"computedHash": "dfbf85749fd474feeb0bbe60c779795ecd5dbec0083299b56e68916bc3ddd8c9"
|
||||||
|
},
|
||||||
|
"caveman-commit": {
|
||||||
|
"source": "JuliusBrussee/caveman",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/caveman-commit/SKILL.md",
|
||||||
|
"computedHash": "f456ea0564875e46858890ac39ee701ecb9c601c72a2da1e6ce6bd5f9fc5d817"
|
||||||
|
},
|
||||||
|
"caveman-compress": {
|
||||||
|
"source": "JuliusBrussee/caveman",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/caveman-compress/SKILL.md",
|
||||||
|
"computedHash": "b8cbfec00b620f0944960a9bb4072f262cf816c1d3c82e6dbded35c30b4c5d0b"
|
||||||
|
},
|
||||||
|
"caveman-help": {
|
||||||
|
"source": "JuliusBrussee/caveman",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/caveman-help/SKILL.md",
|
||||||
|
"computedHash": "2c21437427e98df1eacabaa0b055b5256a308b2191feea3ca2df6a9418e76cb1"
|
||||||
|
},
|
||||||
|
"caveman-review": {
|
||||||
|
"source": "JuliusBrussee/caveman",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/caveman-review/SKILL.md",
|
||||||
|
"computedHash": "fb7214a1c5793bae6ba8b1be4329e2e6f40dbec6dd911dfb335ad29f09c316a1"
|
||||||
|
},
|
||||||
|
"caveman-stats": {
|
||||||
|
"source": "JuliusBrussee/caveman",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/caveman-stats/SKILL.md",
|
||||||
|
"computedHash": "47ce2de3d6cb39a75047b5c962e4eb3da15594e7397c94103e9a104d42626553"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
-20
@@ -1,22 +1,20 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
|
import { Helmet } from 'react-helmet-async';
|
||||||
|
|
||||||
export const NoMatch = () => (
|
export const NoMatch = () => {
|
||||||
<div>
|
return (
|
||||||
<head>
|
<main className="notfound-page">
|
||||||
<title>404 ERROR</title>
|
<Helmet>
|
||||||
</head>
|
<title>404 Error</title>
|
||||||
<body>
|
</Helmet>
|
||||||
<header>
|
|
||||||
<h1>404 ERROR</h1>
|
|
||||||
|
|
||||||
<aside>Hey, you shouldn't be here!</aside>
|
<header>
|
||||||
</header>
|
<h1>404 ERROR</h1>
|
||||||
|
<p>Hey, you shouldn't be here!</p>
|
||||||
<br/>
|
</header>
|
||||||
|
<section>
|
||||||
<h2>Don't know how you got here but you should probably turn around and head back.</h2>
|
<p>Don't know how you got here, but you should probably head back.</p>
|
||||||
|
</section>
|
||||||
<p>There's nothing here!</p>
|
</main>
|
||||||
</body>
|
);
|
||||||
</div>
|
};
|
||||||
)
|
|
||||||
|
|||||||
+20
-23
@@ -1,5 +1,6 @@
|
|||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
|
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
|
||||||
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
import { Home } from './Home';
|
import { Home } from './Home';
|
||||||
import { Resume } from './Resume';
|
import { Resume } from './Resume';
|
||||||
import { Projects } from './Projects';
|
import { Projects } from './Projects';
|
||||||
@@ -10,27 +11,23 @@ import { NavigationBar } from './components/NavigationBar';
|
|||||||
import { Jumbotron } from './components/Jumbotron';
|
import { Jumbotron } from './components/Jumbotron';
|
||||||
import Footer from './components/Footer';
|
import Footer from './components/Footer';
|
||||||
|
|
||||||
class App extends Component {
|
const App = () => (
|
||||||
render() {
|
<HelmetProvider>
|
||||||
return (
|
<Router>
|
||||||
<React.Fragment>
|
<NavigationBar />
|
||||||
<Router>
|
<Jumbotron />
|
||||||
<NavigationBar />
|
<Layout>
|
||||||
<Jumbotron />
|
<Switch>
|
||||||
<Layout>
|
<Route exact path="/" component={Home} />
|
||||||
<Switch>
|
<Route path="/Resume" component={Resume} />
|
||||||
<Route exact path="/" component={Home} />
|
<Route path="/Projects" component={Projects} />
|
||||||
<Route path="/Resume" component={Resume} />
|
<Route path="/Contact" component={Contact} />
|
||||||
<Route path="/Projects" component={Projects} />
|
<Route component={NoMatch} />
|
||||||
<Route path="/Contact" component={Contact} />
|
</Switch>
|
||||||
<Route component={NoMatch} />
|
</Layout>
|
||||||
</Switch>
|
<Footer />
|
||||||
</Layout>
|
</Router>
|
||||||
<Footer />
|
</HelmetProvider>
|
||||||
</Router>
|
);
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
+24
-42
@@ -1,45 +1,27 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
|
import { Helmet } from 'react-helmet-async';
|
||||||
|
|
||||||
export const Contact = () => (
|
export const Contact = () => {
|
||||||
<div>
|
return (
|
||||||
<head>
|
<main className="contact-page">
|
||||||
<title>Contact Info</title>
|
<Helmet>
|
||||||
</head>
|
<title>Contact Gregory Campbell</title>
|
||||||
<body>
|
<meta name="description" content="Contact details for Gregory Campbell." />
|
||||||
<header>
|
</Helmet>
|
||||||
<h1>How to Reach Me</h1>
|
|
||||||
|
|
||||||
<aside>Give me a shout!</aside>
|
<header>
|
||||||
</header>
|
<h1>How to Reach Me</h1>
|
||||||
|
<p>Give me a shout!</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
<br/>
|
<section>
|
||||||
|
<h2>Contact Info</h2>
|
||||||
<h2>Contact Info:</h2>
|
<ul className="contact-list">
|
||||||
|
<li>Email: <a href="mailto:gjcampbell777@gmail.com">gjcampbell777@gmail.com</a></li>
|
||||||
<br/>
|
<li>Phone: <a href="tel:6477797951">(647) 779-7951</a></li>
|
||||||
|
<li>LinkedIn: <a href="https://www.linkedin.com/in/gregoryjcampbell/" target="_blank" rel="noreferrer noopener">Gregory J Campbell</a></li>
|
||||||
<h2>Email:
|
</ul>
|
||||||
<a href="mailto:gjcampbell777@gmail.com">gjcampbell777@gmail.com </a>
|
</section>
|
||||||
</h2>
|
</main>
|
||||||
|
);
|
||||||
<h2>Cell #:
|
};
|
||||||
<a href="tel:6477797951">(647)-779-7951</a>
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<h2>Twitter:
|
|
||||||
<a href="https://twitter.com/Gregory_Soup">@Gregory_Soup</a>
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<h2>LinkedIn:
|
|
||||||
<a href="https://www.linkedin.com/in/gregoryjcampbell/">Gregory J Campbell</a>
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|||||||
+33
-46
@@ -1,50 +1,37 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import Me from './assets/Me.jpeg'
|
import { Helmet } from 'react-helmet-async';
|
||||||
|
import meImage from './assets/Me.jpeg';
|
||||||
|
|
||||||
export const Home = () => (
|
export const Home = () => {
|
||||||
<div>
|
return (
|
||||||
<head>
|
<main className="home-page">
|
||||||
<title>The Works of Gregory Campbell</title>
|
<Helmet>
|
||||||
</head>
|
<title>The Works of Gregory Campbell</title>
|
||||||
<body>
|
<meta name="description" content="Personal website and portfolio of Gregory Campbell." />
|
||||||
|
</Helmet>
|
||||||
|
|
||||||
<h2>Welcome to the personal website of Gregory Campbell</h2>
|
<section>
|
||||||
|
<h2>Welcome to the personal website of Gregory Campbell</h2>
|
||||||
|
<p>I hope you enjoy everything it has to offer.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
<p>I hope you enjoy everything it has to offer</p>
|
<section>
|
||||||
|
<h3>Finished projects viewable on this site</h3>
|
||||||
|
<ul>
|
||||||
|
<li>This website is clean, easy to read, written in React, and adapts well to mobile.</li>
|
||||||
|
<li>I also added a HTML and downloadable PDF version of my resume on the Resume page.</li>
|
||||||
|
<li>Check out the many projects on the Projects tab.</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
<h3>Finished Projects Viewable on this site:</h3>
|
<section>
|
||||||
|
<img
|
||||||
<p></p>
|
src={meImage}
|
||||||
|
alt="Portrait of Gregory Campbell"
|
||||||
<ul>
|
loading="lazy"
|
||||||
<li>This website. It might not seem like much but it's clean, easy to read, is written in reactjs and adapts quite well to mobile.</li>
|
decoding="async"
|
||||||
</ul>
|
/>
|
||||||
|
</section>
|
||||||
<p></p>
|
</main>
|
||||||
|
);
|
||||||
<p></p>
|
};
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>I also added a html and downloadable .pdf version of my resume in the <a href="https://gregoryjcampbell.com/Resume">Resume</a> page, feel free to give it a look!</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p></p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>The many projects that I've mosted in the <a href="https://gregoryjcampbell.com/Projects">Projects</a> tab, go check it out!</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p></p>
|
|
||||||
|
|
||||||
<blockquote></blockquote>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<img src={Me} alt="It's Me!" className="homeimage"/>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
</body>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|||||||
+153
-236
@@ -1,236 +1,153 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import ShowingOff from './assets/ShowingOff.jpg'
|
import { Helmet } from 'react-helmet-async';
|
||||||
import MJB from './assets/MJB.jpg'
|
import ProjectCard from './components/ProjectCard';
|
||||||
import GC from './assets/GunControl.png'
|
|
||||||
import Palish from './assets/Palish.png'
|
// Import all project images
|
||||||
import SRS from './assets/SRS.png'
|
import StateMachine from './assets/StateMachine.png';
|
||||||
import WH from './assets/W&H.png'
|
import HSV from './assets/HSV.png';
|
||||||
import StateMachine from './assets/StateMachine.png'
|
import skin2 from './assets/skin2.png';
|
||||||
import Skin2 from './assets/skin2.png'
|
import EulerExample from './assets/EulerExample.png';
|
||||||
import HSV from './assets/HSV.png'
|
import EulerCycle from './assets/EulerCycle.png';
|
||||||
import EulerCycle from './assets/EulerCycle.png'
|
import Hangman from './assets/Hangman.png';
|
||||||
import EulerExample from './assets/EulerExample.png'
|
import KnightsTour from './assets/KnightsTour.png';
|
||||||
import Hangman from './assets/Hangman.png'
|
import TextAnalyzer from './assets/TextAnalyzer.png';
|
||||||
import KngihtsTour from './assets/KnightsTour.png'
|
import AlgorithmComparison from './assets/AlgorithmComparison.png';
|
||||||
import TextAnalyzer from './assets/TextAnalyzer.png'
|
import ShowingOff from './assets/ShowingOff.jpg';
|
||||||
import AlgorithmComparison from './assets/AlgorithmComparison.png'
|
import MJB from './assets/MJB.jpg';
|
||||||
|
import GunControl from './assets/GunControl.png';
|
||||||
export const Projects = () => (
|
import Palish from './assets/Palish.png';
|
||||||
<div>
|
import WH from './assets/W&H.png';
|
||||||
<head>
|
import SRS from './assets/SRS.png';
|
||||||
<title>The Projects of Gregory Campbell</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
// Map imgName to imported images
|
||||||
<header>
|
const imageMap = {
|
||||||
<h1>My Projects</h1>
|
StateMachine,
|
||||||
|
HSV,
|
||||||
<aside>Look at what I've created!</aside>
|
skin2,
|
||||||
</header>
|
EulerExample,
|
||||||
|
EulerCycle,
|
||||||
<br/>
|
Hangman,
|
||||||
|
KnightsTour,
|
||||||
<h2>This page contains the projects I've done over the past, present and future.</h2>
|
TextAnalyzer,
|
||||||
|
AlgorithmComparison,
|
||||||
<br/>
|
ShowingOff,
|
||||||
|
MJB,
|
||||||
<hr/>
|
GunControl,
|
||||||
|
Palish,
|
||||||
<h4>If you want to see what I'm currently working on you can see all my updates
|
WH,
|
||||||
<a href="https://twitter.com/Gregory_Soup">Here</a>
|
SRS
|
||||||
</h4>
|
};
|
||||||
|
|
||||||
<hr/>
|
const projects = [
|
||||||
<h3> <a href="https://github.com/gjcampbell777/python-state-machine">Python State Machine</a> </h3>
|
{
|
||||||
|
title: 'Python State Machine',
|
||||||
<br/>
|
link: 'https://github.com/gjcampbell777/python-state-machine',
|
||||||
|
description: 'A Python state machine used to emulate a locked/unlocked device.',
|
||||||
<p>Recently while going through Godot documentation I came across a tutorial for building your own state machine with Python.
|
imgName: 'StateMachine',
|
||||||
I've always been interested in making a stand alone state machine and state machines are a big part of game developement
|
imgAlt: 'Python state machine demo'
|
||||||
so I figured it would be a good idea for me to check it out. After I finished the tutorial I decided to continue working on
|
},
|
||||||
and fleshing out this state machine used to emulate a locked/unlocked device.
|
{
|
||||||
You can check out my code and mess around with the state machine yourself <a href="https://github.com/gjcampbell777/python-state-machine">Here</a>.
|
title: 'Python Skin Detection Algorithms',
|
||||||
</p>
|
link: 'https://github.com/gjcampbell777/python-photo-skin-detection',
|
||||||
|
description: 'Replicated multiple skin detection algorithms in Python and modernized them for Python 3.',
|
||||||
<img src={StateMachine} alt="StateMachine"/>
|
imgName: 'HSV',
|
||||||
|
imgAlt: 'Skin detection image after',
|
||||||
<br/><br/>
|
},
|
||||||
|
{
|
||||||
<h3> <a href="https://github.com/gjcampbell777/python-photo-skin-detection">Python Skin Detection Algorithms</a> </h3>
|
imgName: 'skin2',
|
||||||
|
imgAlt: 'Skin detection image before',
|
||||||
<br/>
|
},
|
||||||
|
{
|
||||||
<p>In an image processing course I took in university we were tasked with replicating multiple skin detection algorithms through a python script.
|
title: 'Euler Checking Algorithm',
|
||||||
I enjoyed working on that assignment and was fascinated by how well (or not so well) a program is able to detect things that we as humans can figure out easily.
|
link: 'https://github.com/gjcampbell777/euler-checking-algorithm',
|
||||||
It's one of the few assignments I worked on in university that I can still remember quite well so I figured I'd find it wherever I had saved it
|
description: 'C program to check if graphs are Eulerian.',
|
||||||
and clean it up as well as make sure it can run with python3.
|
imgName: 'EulerExample',
|
||||||
You can check out my code and run your own photos through the script by checking out the repo <a href="https://github.com/gjcampbell777/python-photo-skin-detection">Here</a>.
|
imgAlt: 'Euler example'
|
||||||
</p>
|
},
|
||||||
|
{
|
||||||
<img src={Skin2} alt="Before"/>
|
imgName: 'EulerCycle',
|
||||||
|
imgAlt: 'Euler cycle output',
|
||||||
<p>Before going through the algorithm</p>
|
},
|
||||||
|
{
|
||||||
<br/>
|
title: 'Fortran Hangman',
|
||||||
|
link: 'https://github.com/gjcampbell777/fortran-hangman',
|
||||||
<img src={HSV} alt="After"/>
|
description: 'Updated a Fortran 77 hangman game to Fortran 95 and improved the code.',
|
||||||
|
imgName: 'Hangman',
|
||||||
<p>After going through the HSV algorithm</p>
|
imgAlt: 'Hangman game'
|
||||||
|
},
|
||||||
<br/>
|
{
|
||||||
|
title: "Ada Knights Tour",
|
||||||
<h3> <a href="https://github.com/gjcampbell777/euler-checking-algorithm">Euler Checking Algorithm</a> </h3>
|
link: 'https://github.com/gjcampbell777/ada-knights-tour',
|
||||||
|
description: "Solves the knight's tour problem in Ada.",
|
||||||
<br/>
|
imgName: 'KnightsTour',
|
||||||
|
imgAlt: 'Knights tour output'
|
||||||
<p>In a course I took in university we were tasked checking if a graph was Eulerian or not.
|
},
|
||||||
Much like the Python Skin Detection assignment this was also an assignment I could still remember
|
{
|
||||||
from those days and wanted to re-explore and improve upon.
|
title: 'COBOL Text Analyzer',
|
||||||
This C algorithm takes the text file euler-graphs.txt and runs through the input to determine if its contents contain a Euler graph.
|
link: 'https://github.com/gjcampbell777/cobol-text-analyzer',
|
||||||
The algorithm checks the initial line of a graph to determine the length of the graph and
|
description: 'Modernized COBOL text analyzer to report text statistics.',
|
||||||
uses that information to know how many lines it must go through to gather all the info of the graph.
|
imgName: 'TextAnalyzer',
|
||||||
It will repeat this process until it reaches EOF.
|
imgAlt: 'Text analyzer output'
|
||||||
You can check out my code by checking out the repo <a href="https://github.com/gjcampbell777/euler-checking-algorithm">Here</a>.
|
},
|
||||||
</p>
|
{
|
||||||
|
title: 'Legacy Algorithm Comparison',
|
||||||
<br/>
|
link: 'https://github.com/gjcampbell777/legacy-algorithm-comparison',
|
||||||
|
description: 'Compare KMP implementations across C, Fortran, and Ada.',
|
||||||
<img src={EulerExample} alt="EulerExample"/>
|
imgName: 'AlgorithmComparison',
|
||||||
|
imgAlt: 'Algorithm comparison charts'
|
||||||
<p>Example of a graph from euler-graphs.txt</p>
|
},
|
||||||
|
{
|
||||||
<br/>
|
title: 'My Many Games',
|
||||||
|
description: 'A selection of games made with Unity and Godot.',
|
||||||
<img src={EulerCycle} alt="EulerCycle"/>
|
imgName: 'ShowingOff',
|
||||||
|
imgAlt: 'Game showcase'
|
||||||
<p>Output from running the algorithm with euler-graphs.txt</p>
|
},
|
||||||
|
{
|
||||||
<br/>
|
imgName: 'MJB',
|
||||||
|
imgAlt: 'Magical Jumping Bean'
|
||||||
<h3> <a href="https://github.com/gjcampbell777/fortran-hangman">Fortran Hangman</a> </h3>
|
},
|
||||||
|
{
|
||||||
<br/>
|
imgName: 'GunControl',
|
||||||
|
imgAlt: 'Gun Control'
|
||||||
<p>In a legacy programming course I took in university we were tasked with updating a fortran77 hangman program to fortran95
|
},
|
||||||
as well as improving upon the code itself.
|
{
|
||||||
Much like some of the other projects above this was also an assignment I could still remember
|
imgName: 'Palish',
|
||||||
from those days and wanted to re-explore and improve upon.
|
imgAlt: 'Palish'
|
||||||
Run the executable to play a simple game of hangman.
|
},
|
||||||
You can even use the makefile I added to generate an executable of the fortran77 version.
|
{
|
||||||
You can check out my code for this project <a href="https://github.com/gjcampbell777/fortran-hangman">Here</a>.
|
imgName: 'WH',
|
||||||
</p>
|
imgAlt: 'Wally And Harv Escape the Fireball and Brick Factory'
|
||||||
|
},
|
||||||
<br/>
|
{
|
||||||
|
imgName: 'SRS',
|
||||||
<img src={Hangman} alt="Hangman"/>
|
imgAlt: 'Super Robo Squad'
|
||||||
<p>A very quick game of hangman</p>
|
},
|
||||||
|
];
|
||||||
<br/>
|
|
||||||
|
export const Projects = () => {
|
||||||
<h3> <a href="https://github.com/gjcampbell777/ada-knights-tour">Ada Kngihts Tour</a> </h3>
|
|
||||||
|
return (
|
||||||
<br/>
|
<main className="projects-page">
|
||||||
|
<Helmet>
|
||||||
<p>In a legacy programming course I took in university we were tasked with creating a program that could solve the knights tour problem using Ada.
|
<title>The Projects of Gregory Campbell</title>
|
||||||
Much like some of the other projects above this was also an assignment I could still remember
|
<meta name="description" content="Collection of projects by Gregory Campbell." />
|
||||||
from those days and wanted to re-explore and improve upon.
|
</Helmet>
|
||||||
Run the executable and follow the prompts to have the program solve the problem for you.
|
<header>
|
||||||
However you should try to not make the chessboard size bigger than 7 if you don't have time to spare.
|
<h1>My Projects</h1>
|
||||||
You can check out my code for this project <a href="https://github.com/gjcampbell777/ada-knights-tour">Here</a>.
|
<aside>Look at what I've created!</aside>
|
||||||
</p>
|
</header>
|
||||||
|
|
||||||
<br/>
|
{projects.map((p) => (
|
||||||
|
<ProjectCard
|
||||||
<img src={KngihtsTour} alt="KnightsTour"/>
|
key={p.title}
|
||||||
|
title={p.title}
|
||||||
<p>Knights tour output for a 5x5 chessboard starting at position (1,1)</p>
|
description={p.description}
|
||||||
|
imgSrc={imageMap[p.imgName]}
|
||||||
<br/>
|
imgAlt={p.imgAlt}
|
||||||
|
link={p.link}
|
||||||
<h3> <a href="https://github.com/gjcampbell777/cobol-text-analyzer">Cobol Text Analyzer</a> </h3>
|
/>
|
||||||
|
))}
|
||||||
<br/>
|
</main>
|
||||||
|
);
|
||||||
<p>In a legacy programming course I took in university we were tasked with improving upon a cobol script that
|
};
|
||||||
was full of dated coding practices.
|
|
||||||
Much like some of the other projects above this was also an assignment I could still remember
|
|
||||||
from those days and wanted to re-explore and improve upon.
|
|
||||||
Run the executable and tell it which textfile you wish to have analyzed to see the text stats.
|
|
||||||
You can even use the makefile I added to generate an executable of the dated script.
|
|
||||||
However the text file that script takes is hard coded so you will have to change some things around if you want to analyze different text with it.
|
|
||||||
You can check out my code for this project <a href="https://github.com/gjcampbell777/cobol-text-analyzer">Here</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<img src={TextAnalyzer} alt="TextAnalyzer"/>
|
|
||||||
|
|
||||||
<p>Analyzing some text from Star Wars</p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<h3> <a href="https://github.com/gjcampbell777/legacy-algorithm-comparison">Legacy Code Algorithm Comparison</a> </h3>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<p>In a legacy programming course I took in university we were tasked with comparing the speeds of C, Fortran and Ada using the KMP search algorithm.
|
|
||||||
Much like some of the other projects above this was also an assignment I could still remember
|
|
||||||
from those days and wanted to re-explore and improve upon.
|
|
||||||
Run the executable of your choice to see the speed of that coding language.
|
|
||||||
Using the makefile I created generates executables for each programming language.
|
|
||||||
You can check out my code for this project <a href="https://github.com/gjcampbell777/legacy-algorithm-comparison">Here</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<img src={AlgorithmComparison} alt="AlgorithmComparison"/>
|
|
||||||
|
|
||||||
<p>Seeing how quickly C, Fortran and Ada are all able to find "Q" in a block of text</p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<h3> <a href="https://gregorysoup.itch.io">My Many Games</a> </h3>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<p>Over the course of the last decade I've made a handful of games on my own.
|
|
||||||
I've always been interested in game developement and I use this as a way to experiment and
|
|
||||||
create games I would like to play myself. The fact that I've made all these games on my own allows me
|
|
||||||
to go at my own pace as well as learn every aspect there is to this type of development while still being able to put my own charm into each game I make.
|
|
||||||
I've worked on a fast paced endless runner 3D platformer, a 2D turn based combat puzzle and many game jam games.
|
|
||||||
I continue to explore and create new game ideas as they pop into my head, so be sure to be on the look out for what I make next.
|
|
||||||
Any game I've worked on has either been created using Unity or Godot which both utilize their own proprietary coding languages.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<img src={ShowingOff} alt="Presenting my game at a toronto indie game dev meet up"/>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<img src={MJB} alt="MJB"/>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<img src={WH} alt="WH"/>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<img src={SRS} alt="SRS"/>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<img src={Palish} alt="Palish"/>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<img src={GC} alt="GC"/>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
+78
-93
@@ -1,103 +1,88 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import pdf from './assets/Gregory Campbell Resume.pdf'
|
import { Helmet } from 'react-helmet-async';
|
||||||
import pic from './assets/Resume.png'
|
import pdf from './assets/Gregory Campbell Resume.pdf';
|
||||||
|
import resumeImage from './assets/Resume.png';
|
||||||
|
|
||||||
export const Resume = () => (
|
export const Resume = () => {
|
||||||
<div>
|
return (
|
||||||
<head>
|
<main className="resume-page">
|
||||||
<title>The Resume of Gregory Campbell</title>
|
<Helmet>
|
||||||
</head>
|
<title>The Resume of Gregory Campbell</title>
|
||||||
<body>
|
<meta name="description" content="Resume and professional experience of Gregory Campbell." />
|
||||||
<header>
|
</Helmet>
|
||||||
<h1>My Resume</h1>
|
|
||||||
|
|
||||||
<aside>Check out everything I have accomplished in my career.</aside>
|
<header>
|
||||||
</header>
|
<h1>My Resume</h1>
|
||||||
|
<p>Check out everything I have accomplished in my career.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
<br/>
|
<section>
|
||||||
|
<h2>Downloadable PDF</h2>
|
||||||
|
<p>
|
||||||
|
You can view and download a PDF version of my resume{' '}
|
||||||
|
<a href={pdf} target="_blank" rel="noreferrer noopener">here</a>.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
<h2>Downloadable PDF</h2>
|
<section>
|
||||||
|
<h2>Written Resume</h2>
|
||||||
|
<img
|
||||||
|
src={resumeImage}
|
||||||
|
alt="Resume preview"
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
|
||||||
<p>You can view and download a .pdf verison of my resume <a href={pdf}>Here</a></p>
|
<section>
|
||||||
|
<h2>Gregory Campbell</h2>
|
||||||
|
<p>
|
||||||
|
<a href="tel:6477797951">(647) 779-7951</a> ·{' '}
|
||||||
|
<a href="mailto:gjcampbell777@gmail.com">gjcampbell777@gmail.com</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
<br/>
|
<h3>Profile</h3>
|
||||||
|
<p>Highly motivated and team-focused software developer with 4+ years of experience developing code and creating test environments and infrastructure.</p>
|
||||||
|
|
||||||
<h2><u>Resume</u></h2>
|
<h3>Education</h3>
|
||||||
|
<p>
|
||||||
|
<strong>Bachelor of Computing, Computer Science (Co-op)</strong><br />
|
||||||
|
<em>University of Guelph – Guelph, Ontario</em><br />
|
||||||
|
Completed April 2017
|
||||||
|
</p>
|
||||||
|
|
||||||
<br/>
|
<h3>Work Experience</h3>
|
||||||
|
<article>
|
||||||
|
<h4>Software Developer</h4>
|
||||||
|
<p><em>Clear Blue Technologies – North York, Ontario</em> · Aug 2017 - Present</p>
|
||||||
|
<ul>
|
||||||
|
<li>Added features and fixed issues with various controllers using the functional programming language Elixir.</li>
|
||||||
|
<li>Built automated black box testing devices and infrastructure with controller code, Raspberry Pi, and programmable power supplies.</li>
|
||||||
|
<li>Developed automated black box front end testing across Chrome, Firefox, and Safari using TestCafe.</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
<img src={pic} alt="Resume"/>
|
<article>
|
||||||
|
<h4>Software Test Specialist</h4>
|
||||||
|
<p><em>IBM (AppScan Source team) – Markham, Ontario</em> · Jun 2014 - Aug 2016</p>
|
||||||
|
<ul>
|
||||||
|
<li>Created a test tool in HTML and JavaScript to help developers efficiently test builds using subsets of smoke tests.</li>
|
||||||
|
<li>Presented security findings to stakeholders, architects, and developers.</li>
|
||||||
|
<li>Integrated the Juliet test suite into AppScan Source test automation using Java.</li>
|
||||||
|
<li>Developed, debugged, executed, and maintained Bash testing scripts.</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
<br/>
|
<h3>Technical Skills</h3>
|
||||||
|
<ul>
|
||||||
<h2><u>Written Resume</u></h2>
|
<li>Programming Languages: Elixir, C, C#, Java, Python, Fortran, Ada, Cobol</li>
|
||||||
|
<li>Web Design and Coding: HTML, JavaScript, ReactJS, CSS, Node.js, jQuery</li>
|
||||||
<br/>
|
<li>Software Environments: Windows, Mac, Linux, Unity, Godot, VirtualBox, Docker</li>
|
||||||
|
<li>Automation tools: Bash, TestCafe, ExUnit, Jenkins, GitLab CI, Python scripting</li>
|
||||||
<h2>Gregory Campbell</h2>
|
<li>Experience with security testing, vulnerabilities, and application design in agile environments</li>
|
||||||
|
<li>Version control: GitHub, GitLab, Bitbucket</li>
|
||||||
<p align="right">
|
</ul>
|
||||||
<a href="tel:6477797951">(647)-779-7951</a><br />
|
</section>
|
||||||
<b><a href="mailto:gjcampbell777@gmail.com">gjcampbell777@gmail.com </a></b>
|
</main>
|
||||||
</p>
|
);
|
||||||
|
};
|
||||||
<h3><u>Profile:</u></h3>
|
|
||||||
|
|
||||||
<p>Highly motivated and team-focused software developer with 4+ years of experience developing code and creating test environments and infrastructure.</p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<h3><u>Education:</u></h3>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<p><b>Bachelor of Computing, Computer Science (Co-op)</b><br />
|
|
||||||
<i>University of Guelph – Guelph, Ontario</i> <span>Completed April 2017 </span></p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<h3><u>Work Experience</u></h3>
|
|
||||||
|
|
||||||
<p><b>Software Developer,</b><br />
|
|
||||||
<i>Clear Blue Technologies – North York, Ontario</i> <span>Aug 2017 - Present </span></p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Adding features and fixing issues with various controllers using the functional programming language Elixir.</li>
|
|
||||||
<li>Built multiple varieties of automated black box testing devices and accompanying infrastructure with the controller, a raspberry pi, a programmable power supply and elixir code from scratch.</li>
|
|
||||||
<li>Developed automated black box front end testing infrastructure of the company web service across Chrome, Firefox and Safari using the node.js automation tool "Testcafe".</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p><b>Software Test Specialist,</b><br />
|
|
||||||
<i>IBM (Appscan Source team) – Markham, Ontario</i> <span>Jun 2014 - Aug 2016 </span></p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Created a test tool in HTML and Javascript with API usage for developers to more efficiently test builds using subsets of smoke tests.</li>
|
|
||||||
<li>Multiple presentations to stakeholders, architects and developers on security vulnerabilities, demoed security programs. </li>
|
|
||||||
<li>Integrated Juliet test suite into the Appscan Source test automation system using Java.</li>
|
|
||||||
<li>Developed, debugged, executed and maintained bash testing scripts.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<h3><u>Technical Skills:</u></h3>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Programming Languages: Elixir, C, C#, Java, Python, Fortran, Ada, Cobol</li>
|
|
||||||
<li>Web Design and Coding: HTML, Javascript, ReactJs, CSS, Node.js, JQuery</li>
|
|
||||||
<li>Software Environments: Windows, Mac, Linux, Unity, Godot, VirtualBox, Terminal/Console, Docker</li>
|
|
||||||
<li>Various automation tools such as Bash, Testcafe, ExUnit, Jenkins, Gitlab CI and Python scripting</li>
|
|
||||||
<li>Knowledge and experience with computer security, security vulnerabilities and security testing</li>
|
|
||||||
<li>Well versed in application design, development and testing within an agile development cycle</li>
|
|
||||||
<li>Expertise using SVN such as Github, Gitlab and Bitbucket within team and solo projects</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<br/><br/>
|
|
||||||
|
|
||||||
<blockquote></blockquote>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
</body>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|||||||
+16
-30
@@ -4,36 +4,22 @@ import linkedin from "./../assets/LI-Logo.png";
|
|||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<footer className="footer">
|
||||||
<nav className="footer">
|
<div className="footer-links">
|
||||||
<div className="footer-links">
|
<ul>
|
||||||
<ul>
|
<li>
|
||||||
<li>
|
<a href="https://github.com/gjcampbell777" target="_blank" rel="noreferrer noopener">
|
||||||
<a href="https://github.com/gjcampbell777">
|
<img src={github} alt="GitHub profile" />
|
||||||
<img
|
</a>
|
||||||
src={github}
|
</li>
|
||||||
alt="Github Logo"
|
<li>
|
||||||
height="auto"
|
<a href="https://www.linkedin.com/in/gregoryjcampbell/" target="_blank" rel="noreferrer noopener">
|
||||||
width="100%"
|
<img src={linkedin} alt="LinkedIn profile" />
|
||||||
style={{ maxWidth: "80px" }}
|
</a>
|
||||||
/>
|
</li>
|
||||||
</a>
|
</ul>
|
||||||
</li>
|
</div>
|
||||||
<li>
|
</footer>
|
||||||
<a href="https://www.linkedin.com/in/gregoryjcampbell/">
|
|
||||||
<img
|
|
||||||
src={linkedin}
|
|
||||||
alt="LinkedIn Logo"
|
|
||||||
height="auto"
|
|
||||||
width="100%"
|
|
||||||
style={{ maxWidth: "115px" }}
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,30 +20,22 @@ const Styles = styled.div`
|
|||||||
|
|
||||||
export const NavigationBar = () => (
|
export const NavigationBar = () => (
|
||||||
<Styles>
|
<Styles>
|
||||||
<Navbar expand="lg" color='light-blue lighten-4'>
|
<Navbar expand="lg" bg="light" variant="light">
|
||||||
<Navbar.Brand as={Link} to="/">GC</Navbar.Brand>
|
<Navbar.Brand as={Link} to="/">GC</Navbar.Brand>
|
||||||
<Navbar.Toggle aria-controls="basic-navbar-nav" />
|
<Navbar.Toggle aria-controls="basic-navbar-nav" />
|
||||||
<Navbar.Collapse id="basic-navbar-nav">
|
<Navbar.Collapse id="basic-navbar-nav">
|
||||||
<Nav classname="navbar-link">
|
<Nav className="navbar-link">
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Nav.Link as={Link} to="/">
|
<Nav.Link as={Link} to="/">Home</Nav.Link>
|
||||||
<Link to="/">Home</Link>
|
|
||||||
</Nav.Link>
|
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Nav.Link as={Link} to="/Resume">
|
<Nav.Link as={Link} to="/Resume">Resume</Nav.Link>
|
||||||
<Link to="/Resume">Resume</Link>
|
|
||||||
</Nav.Link>
|
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Nav.Link as={Link} to="/Projects">
|
<Nav.Link as={Link} to="/Projects">Projects</Nav.Link>
|
||||||
<Link to="/Projects">Projects</Link>
|
|
||||||
</Nav.Link>
|
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Nav.Link as={Link} to="/Contact">
|
<Nav.Link as={Link} to="/Contact">Contact</Nav.Link>
|
||||||
<Link to="/Contact">Contact</Link>
|
|
||||||
</Nav.Link>
|
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
</Nav>
|
</Nav>
|
||||||
</Navbar.Collapse>
|
</Navbar.Collapse>
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const ProjectCard = ({ title, description, imgSrc, imgAlt, link, children }) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<article className="project-card">
|
||||||
|
<h3>{link ? <a href={link} target="_blank" rel="noreferrer noopener">{title}</a> : title}</h3>
|
||||||
|
<p>{description}</p>
|
||||||
|
{imgSrc && (
|
||||||
|
<img
|
||||||
|
src={imgSrc}
|
||||||
|
alt={imgAlt || title}
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProjectCard;
|
||||||
+20
-15
@@ -12,32 +12,30 @@ code {
|
|||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
a {
|
||||||
display: inline-block;
|
|
||||||
width: 15%;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
a{
|
|
||||||
color: #000;
|
color: #000;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
color: #219837
|
color: #219837;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
display: block;
|
display: block;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
width: 100%;
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.homeimage{
|
.homeimage {
|
||||||
display: block;
|
display: block;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
width: auto;
|
max-width: 480px;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.iframe-container {
|
.iframe-container {
|
||||||
@@ -58,10 +56,9 @@ img {
|
|||||||
.footer {
|
.footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: sticky;
|
position: relative;
|
||||||
top: 0;
|
padding: 1rem 0;
|
||||||
color: white;
|
color: #000;
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-links ul {
|
.footer-links ul {
|
||||||
@@ -83,4 +80,12 @@ img {
|
|||||||
|
|
||||||
.footer-links li:hover {
|
.footer-links li:hover {
|
||||||
background-color: #b2b2b2;
|
background-color: #b2b2b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Constrain footer images so they don't become massive */
|
||||||
|
.footer-links img {
|
||||||
|
display: inline-block;
|
||||||
|
max-height: 120px;
|
||||||
|
width: auto;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user