+6
-107
@@ -9,118 +9,17 @@ import "./main.css";
|
|||||||
* Primary portfolio application. Utilizes swiper.js (via /components/VerticalSlider.jsx) to
|
* Primary portfolio application. Utilizes swiper.js (via /components/VerticalSlider.jsx) to
|
||||||
* have a scrolling section to section effect.
|
* have a scrolling section to section effect.
|
||||||
*
|
*
|
||||||
* This is the primary place where (currently) application data is stored. This information will be read in
|
* Managed by /main.jsx.
|
||||||
* from plain-text files in the future for ease of future editing. In the meantime, generated components,
|
* Data by /main.jsx.
|
||||||
* specifically the Skill Card and Project Card (see /components/SkillCard.jsx and /components/ProjectCard.jsx)
|
|
||||||
* get their data from here and thus any additions are made in this file.
|
|
||||||
*
|
*
|
||||||
* TODO: Read in data from a plain text file for easier editing in the future, and to separate domains.
|
* @param projectData JSON[], data necessary to create project cards.
|
||||||
|
* @param skillData JSON, data necessary to create skill cards.
|
||||||
*/
|
*/
|
||||||
const App = () => {
|
const App = ({ projectData, skillData }) => {
|
||||||
// DATA VARIABLES
|
|
||||||
const projectData = [
|
|
||||||
{
|
|
||||||
title: "One AI",
|
|
||||||
description:
|
|
||||||
"An end-to-end self-hosted Artificial Intelligence solution, using Meta's Ollama platform to run Large Language Models. Go was used for the backend as a wrapper API and the frontend is Flutter. Here are some of the implemented features:",
|
|
||||||
featureList: [
|
|
||||||
"AES encryption of messages between client and server",
|
|
||||||
"SHA-256 hashing for message validation",
|
|
||||||
"Base64 encoding for file uploads to the server",
|
|
||||||
"Docker container for isolation and security",
|
|
||||||
],
|
|
||||||
image: "/images/one-ai-cropped.png",
|
|
||||||
imageGallery: null,
|
|
||||||
url: "https://github.com/quaxlyqueen/one-ai",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Snake",
|
|
||||||
description:
|
|
||||||
"A Snake clone in the command line, written in C#. Utilized a Queue data structure to keep track of the snake's body. Implemented features include:",
|
|
||||||
featureList: [
|
|
||||||
"basic pseudo-randomized obstacle generation",
|
|
||||||
"difficulty selection by adjusting the frequency of obstacle generation",
|
|
||||||
"keyboard input to move the snake",
|
|
||||||
"ASCII art for the menu and game over state",
|
|
||||||
],
|
|
||||||
image: "/images/snake.gif",
|
|
||||||
imageGallery: null,
|
|
||||||
url: "https://github.com/quaxlyqueen/2410-Snake",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Battery Monitor",
|
|
||||||
description:
|
|
||||||
"A battery monitor, written in C with a GUI written in Python. Utilizes the acpi Unix command to gather battery information. Implemented features incldue:",
|
|
||||||
featureList: [
|
|
||||||
"embed Unix commands in C to get the date, time, battery percentage, and battery status",
|
|
||||||
"basic file I/O to store historical battery data",
|
|
||||||
"daemonize to run as a background process",
|
|
||||||
"script to install as a SystemD service",
|
|
||||||
"basic Python GUI in TKinter to provide graph of data",
|
|
||||||
],
|
|
||||||
image: "/images/battery-mon.png",
|
|
||||||
imageGallery: null,
|
|
||||||
url: "https://github.com/quaxlyqueen/battery-mon",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "D&D Character Builder",
|
|
||||||
description:
|
|
||||||
"A Dungeons and Dragons character builder, following the 5th edition rules and creation process. A collaborative project creating a GUI in Java with Swing. Features include:",
|
|
||||||
featureList: [
|
|
||||||
"serialization of character data into custom filetype",
|
|
||||||
"global styling and custom font import",
|
|
||||||
"button hover effects",
|
|
||||||
],
|
|
||||||
image: "/images/dnd.png",
|
|
||||||
imageGallery: null,
|
|
||||||
url: "https://github.com/quaxlyqueen/dnd",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Calculator",
|
|
||||||
description:
|
|
||||||
"A simple and themable calculator written in Python. This uses CustomTKinter for the GUI and the eva CLI package for the actual calculator functionality. Supports MacOS and Linux. Implemented features include:",
|
|
||||||
featureList: [
|
|
||||||
"custom theming read in from a global .theme file",
|
|
||||||
"button hover effects",
|
|
||||||
"keyboard input",
|
|
||||||
],
|
|
||||||
image: "/images/calculator.gif",
|
|
||||||
imageGallery: null,
|
|
||||||
url: "https://github.com/quaxlyqueen/calculator",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const skillsData = {
|
|
||||||
languages: [
|
|
||||||
"C & C#",
|
|
||||||
"HTML & CSS",
|
|
||||||
"Go",
|
|
||||||
"Java",
|
|
||||||
"JavaScript & Dart",
|
|
||||||
"Python",
|
|
||||||
],
|
|
||||||
tools: [
|
|
||||||
"Git & GitHub",
|
|
||||||
"Docker",
|
|
||||||
"Flutter & React",
|
|
||||||
"Linux & NeoVim",
|
|
||||||
"Cloudflare",
|
|
||||||
"Microsoft Intune",
|
|
||||||
],
|
|
||||||
other: [
|
|
||||||
"Written Communication",
|
|
||||||
"Conflict Resolution",
|
|
||||||
"Project Management",
|
|
||||||
"Event Planning",
|
|
||||||
"Electronics Repair",
|
|
||||||
"Soldering",
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const slides = [
|
const slides = [
|
||||||
<Home
|
<Home
|
||||||
image="/images/profile.jpg"
|
image="/images/profile.jpg"
|
||||||
skills={skillsData}
|
skills={skillData}
|
||||||
/>,
|
/>,
|
||||||
<Projects cardData={projectData} />,
|
<Projects cardData={projectData} />,
|
||||||
<Contact />,
|
<Contact />,
|
||||||
|
|||||||
+4
-4
@@ -5,7 +5,7 @@ import SkillCard from "./components/SkillCard";
|
|||||||
* "Home" page/slide of my portfolio.
|
* "Home" page/slide of my portfolio.
|
||||||
*
|
*
|
||||||
* Managed by /App.jsx.
|
* Managed by /App.jsx.
|
||||||
* Data by /App.jsx.
|
* Data by /main.jsx.
|
||||||
*
|
*
|
||||||
* @param image String
|
* @param image String
|
||||||
* @param skills json, containing JSON values of String arrays.
|
* @param skills json, containing JSON values of String arrays.
|
||||||
@@ -18,10 +18,10 @@ const Home = ({ image, skills }) => {
|
|||||||
<>
|
<>
|
||||||
<div id="primary">
|
<div id="primary">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<div className="header-image">
|
<div className="header-image center-row">
|
||||||
<img id="profile" src={image} />
|
<img id="profile" src={image} />
|
||||||
</div>
|
</div>
|
||||||
<div className="header-text">
|
<div className="center-column">
|
||||||
<div className="center-column">
|
<div className="center-column">
|
||||||
<h1>Hi, I'm Josh Ashton.</h1>
|
<h1>Hi, I'm Josh Ashton.</h1>
|
||||||
<h3>Junior full-stack developer.</h3>
|
<h3>Junior full-stack developer.</h3>
|
||||||
@@ -32,7 +32,7 @@ const Home = ({ image, skills }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="skill-cards">
|
<div id="skill-cards">
|
||||||
<div id="card-grid">
|
<div className="center-row">
|
||||||
<SkillCard
|
<SkillCard
|
||||||
header="Languages"
|
header="Languages"
|
||||||
symbol="code"
|
symbol="code"
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import "swiper/css/scrollbar";
|
|||||||
* (see /components/ProjectCard.jsx), generated for each element of the parameter cardData.
|
* (see /components/ProjectCard.jsx), generated for each element of the parameter cardData.
|
||||||
*
|
*
|
||||||
* Managed by /App.jsx.
|
* Managed by /App.jsx.
|
||||||
* Data by /App.jsx.
|
* Data by /main.jsx.
|
||||||
*
|
*
|
||||||
* @param cardData json[], each object contains the following: title, descriptionA, featureList, image, url
|
* @param cardData json[], each object contains the following: title, descriptionA, featureList, image, url
|
||||||
*
|
*
|
||||||
|
|||||||
+85
-8
@@ -1,19 +1,96 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PdfViewer from "./components/PdfViewer";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Page to display my Resume.
|
* Resume page component.
|
||||||
*
|
|
||||||
* TODO: Rework resume to make it one page
|
|
||||||
* TODO: Convert resume to a React component, with a link to save as PDF
|
|
||||||
*/
|
*/
|
||||||
export default function Resume() {
|
const Resume = ({ jobData, eduData, skillData }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div id="resume-section">
|
<div id="resume-section">
|
||||||
<h1>Resume</h1>
|
<h1>Josh Ashton</h1>
|
||||||
<PdfViewer file="resume.pdf" />
|
<h3>Junior Full-Stack Developer</h3>
|
||||||
|
<h3>Work Experience</h3>
|
||||||
|
<div className="jobs">
|
||||||
|
{jobData.map((job, index) => (
|
||||||
|
<Job key={index} company={job.company} title={job.title} start={job.start} end={job.end} location={job.location} responsibilities={job.responsibilities} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<h3>Education</h3>
|
||||||
|
<div className="education-section">
|
||||||
|
{eduData.map((edu, index) => (
|
||||||
|
<Education key={index} institution={edu.institution} degree={edu.degree} gpa={edu.gpa} start={edu.start} end={edu.end} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<h3>Skills</h3>
|
||||||
|
<Skill languages={skillData.languages} tools={skillData.tools} other={skillData.other} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Skill({ languages, tools, other }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="resume-skills">
|
||||||
|
<div className="resume-skills-skill">
|
||||||
|
<h4>Languages:</h4>
|
||||||
|
<p>{languages.join(", ")}</p>
|
||||||
|
</div>
|
||||||
|
<div className="resume-skills-skill">
|
||||||
|
<h4>Tools:</h4>
|
||||||
|
<p>{tools.join(", ")}</p>
|
||||||
|
</div>
|
||||||
|
<div className="resume-skills-skill">
|
||||||
|
<h4>Other:</h4>
|
||||||
|
<p>{other.join(", ")}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Education({ institution, degree, gpa, start, end }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<div className="edu">
|
||||||
|
<div className="edu-header">
|
||||||
|
<div className="edu-header-row">
|
||||||
|
<div className="edu-and-degree">
|
||||||
|
<h4>{institution}</h4>
|
||||||
|
<h6>- {degree}</h6>
|
||||||
|
</div>
|
||||||
|
<h6 className="edu-time">{start} - {end}</h6>
|
||||||
|
</div>
|
||||||
|
<h5>{gpa}</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Job({ company, title, start, end, location, responsibilities }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="job">
|
||||||
|
<div className="job-header">
|
||||||
|
<div className="job-header-row">
|
||||||
|
<div className="company-and-location">
|
||||||
|
<h4>{company} </h4>
|
||||||
|
<h6>- {location}</h6>
|
||||||
|
</div>
|
||||||
|
<h6 className="job-time">{start} - {end}</h6>
|
||||||
|
</div>
|
||||||
|
<h5>{title}</h5>
|
||||||
|
</div>
|
||||||
|
<ul className="job-list">
|
||||||
|
{responsibilities.map((r, index) => (
|
||||||
|
<li key={index} className="job-list-item">{r}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Resume;
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import { Document, Page, pdfjs } from "react-pdf";
|
|
||||||
import "react-pdf/dist/Page/TextLayer.css";
|
|
||||||
import "react-pdf/dist/Page/AnnotationLayer.css";
|
|
||||||
|
|
||||||
export default function PdfViewer({ file }) {
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
|
||||||
"pdfjs-dist/build/pdf.worker.min.mjs",
|
|
||||||
import.meta.url,
|
|
||||||
).toString();
|
|
||||||
|
|
||||||
const [numPages, setNumPages] = useState(0);
|
|
||||||
const [pageNumber, setPageNumber] = useState(1);
|
|
||||||
function prev() {
|
|
||||||
if (pageNumber >= 2) {
|
|
||||||
setPageNumber(pageNumber - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function next() {
|
|
||||||
if (pageNumber < numPages) {
|
|
||||||
setPageNumber(pageNumber + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="pdf-container">
|
|
||||||
<Document
|
|
||||||
file={file}
|
|
||||||
onLoadSuccess={({ numPages: numPagesInPdf }) => {
|
|
||||||
setNumPages(numPagesInPdf);
|
|
||||||
}}
|
|
||||||
className="pdf-document"
|
|
||||||
>
|
|
||||||
<Page pageNumber={pageNumber} scale={0.8} />
|
|
||||||
</Document>
|
|
||||||
<div className="pdf-buttons shadow">
|
|
||||||
<button className="pdf-button" onClick={() => prev()}>
|
|
||||||
<span className="material-icons">arrow_back</span>
|
|
||||||
</button>
|
|
||||||
<button className="pdf-button" onClick={() => next()}>
|
|
||||||
<span className="material-icons">arrow_forward</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@ import React from "react";
|
|||||||
* project.
|
* project.
|
||||||
*
|
*
|
||||||
* Managed by /Projects.jsx.
|
* Managed by /Projects.jsx.
|
||||||
* Data by /App.jsx.
|
* Data by /main.jsx > /App.jsx > /Projects.jsx.
|
||||||
*
|
*
|
||||||
* @param title String
|
* @param title String
|
||||||
* @param description String
|
* @param description String
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import React, { useState, useEffect } from "react";
|
|||||||
*
|
*
|
||||||
* On mobile, only one card at a time may be active. The currently active card is
|
* On mobile, only one card at a time may be active. The currently active card is
|
||||||
* managed by the parent component, Home.jsx, via the isActive and onToggle props.
|
* managed by the parent component, Home.jsx, via the isActive and onToggle props.
|
||||||
|
*
|
||||||
|
* Managed by /Home.jsx.
|
||||||
|
* Data by /main.jsx > /App.jsx > /Home.jsx
|
||||||
*
|
*
|
||||||
* @param header String, the skill card's header
|
* @param header String, the skill card's header
|
||||||
* @param symbol String, a Material Icon from https://fonts.google.com/icons?icon.size=24&icon.color=%23e8eaed
|
* @param symbol String, a Material Icon from https://fonts.google.com/icons?icon.size=24&icon.color=%23e8eaed
|
||||||
@@ -32,7 +35,7 @@ const SkillCard = ({ header, symbol, list, isActive, onToggle }) => {
|
|||||||
<div className="card shadow">
|
<div className="card shadow">
|
||||||
<div className="skill-card-header" onClick={() => onToggle()}>
|
<div className="skill-card-header" onClick={() => onToggle()}>
|
||||||
<span className="material-icons skill-symbol">{symbol}</span>
|
<span className="material-icons skill-symbol">{symbol}</span>
|
||||||
<h3>{header}</h3>
|
<h4>{header}</h4>
|
||||||
</div>
|
</div>
|
||||||
{(isActive || !isMobile) && (
|
{(isActive || !isMobile) && (
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
+110
-25
@@ -41,39 +41,65 @@ body {
|
|||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1,
|
||||||
font-size: clamp(4.25rem, 5.5vw, 10rem);
|
h2,
|
||||||
font-weight: 600;
|
h3,
|
||||||
letter-spacing: 2px;
|
h4,
|
||||||
width: max-content;
|
h5,
|
||||||
|
h6,
|
||||||
|
p,
|
||||||
|
li {
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
h3,
|
h1 {
|
||||||
h4 {
|
font-size: clamp(4rem, 5vw, 10rem);
|
||||||
color: var(--text);
|
font-weight: 600;
|
||||||
font-weight: 300;
|
letter-spacing: 2px;
|
||||||
line-height: 1.5;
|
width: max-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
width: max-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: clamp(2rem, 3vw, 4rem);
|
font-size: clamp(3rem, 4vw, 7rem);
|
||||||
font-weight: 600;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
width: max-content;
|
|
||||||
color: var(--text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-size: clamp(1.5rem, 2vw, 3rem);
|
font-size: clamp(2rem, 3rem, 6rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
font-size: clamp(1rem, 1.5vw, 1.25rem);
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
h5,
|
||||||
font-size: clamp(1rem, 1.5rem, 2rem);
|
h6 {
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: clamp(1rem, 1.5vw, 4rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: clamp(1rem, 1.25vw, 3.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-size: clamp(1rem, 1.125vw, 2rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
li {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: clamp(1rem, 1.1vw, 1.5rem);
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +165,7 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mySwiper {
|
.mySwiper {
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,8 +304,8 @@ p {
|
|||||||
border-radius: 18px 18px 0 0;
|
border-radius: 18px 18px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skill-card-header h3 {
|
.skill-card-header h4 {
|
||||||
font-size: clamp(1.3rem, 2vw, 3rem);
|
font-weight: 700;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +325,6 @@ p {
|
|||||||
|
|
||||||
.card ul li {
|
.card ul li {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
font-size: clamp(1rem, 1.25vw, 1.5rem);
|
|
||||||
color: var(--dark-0);
|
color: var(--dark-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,7 +377,6 @@ p {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-right: 5vw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tooltip container */
|
/* Tooltip container */
|
||||||
@@ -424,6 +448,7 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.project-text p {
|
.project-text p {
|
||||||
|
font-weight: 400;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -447,7 +472,6 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.feature-list li {
|
.feature-list li {
|
||||||
font-size: clamp(1rem, 1.5rem, 2rem);
|
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,6 +554,8 @@ p {
|
|||||||
#resume-section {
|
#resume-section {
|
||||||
margin: 2vw;
|
margin: 2vw;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**PDF Viewer**/
|
/**PDF Viewer**/
|
||||||
@@ -692,6 +718,65 @@ p {
|
|||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jobs,
|
||||||
|
.education-section {
|
||||||
|
border-top: 1px solid var(--accent-0);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job,
|
||||||
|
.edu {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0vw 1vw 1vw 1vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-header-row,
|
||||||
|
.edu-header-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 70% 30%;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-time,
|
||||||
|
.edu-time {
|
||||||
|
justify-self: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-and-location,
|
||||||
|
.edu-and-degree {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-and-location h6,
|
||||||
|
.edu-and-degree h6 {
|
||||||
|
margin-left: .25vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-list {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job-list-item {
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-skills {
|
||||||
|
border-top: 1px solid var(--accent-0);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-skills-skill {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-skills-skill p {
|
||||||
|
margin-left: .5vw;
|
||||||
|
padding: 1vw;
|
||||||
|
}
|
||||||
|
|
||||||
/**Animations**/
|
/**Animations**/
|
||||||
@keyframes background-fade {
|
@keyframes background-fade {
|
||||||
from {
|
from {
|
||||||
|
|||||||
+146
-3
@@ -6,15 +6,158 @@ import Resume from "./Resume.jsx";
|
|||||||
import ErrorPage from "./ErrorPage.jsx";
|
import ErrorPage from "./ErrorPage.jsx";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Root React container and renderer. Also manages the router. Any new pages should be added here.
|
* Root React container and renderer.
|
||||||
|
*
|
||||||
|
* Contains all data and data processing, as well as routing to different pages.
|
||||||
|
* TODO: Read data in from plain text files.
|
||||||
*/
|
*/
|
||||||
const container = document.getElementById("app");
|
const container = document.getElementById("app");
|
||||||
const root = createRoot(container);
|
const root = createRoot(container);
|
||||||
|
|
||||||
|
const projectData = [
|
||||||
|
{
|
||||||
|
title: "One AI",
|
||||||
|
description:
|
||||||
|
"An end-to-end self-hosted Artificial Intelligence solution, using Meta's Ollama platform to run Large Language Models. Go was used for the backend as a wrapper API and the frontend is Flutter. Here are some of the implemented features:",
|
||||||
|
featureList: [
|
||||||
|
"AES encryption of messages between client and server",
|
||||||
|
"SHA-256 hashing for message validation",
|
||||||
|
"Base64 encoding for file uploads to the server",
|
||||||
|
"Docker container for isolation and security",
|
||||||
|
],
|
||||||
|
image: "/images/one-ai-cropped.png",
|
||||||
|
imageGallery: null,
|
||||||
|
url: "https://github.com/quaxlyqueen/one-ai",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Snake",
|
||||||
|
description:
|
||||||
|
"A Snake clone in the command line, written in C#. Utilized a Queue data structure to keep track of the snake's body. Implemented features include:",
|
||||||
|
featureList: [
|
||||||
|
"basic pseudo-randomized obstacle generation",
|
||||||
|
"difficulty selection by adjusting the frequency of obstacle generation",
|
||||||
|
"keyboard input to move the snake",
|
||||||
|
"ASCII art for the menu and game over state",
|
||||||
|
],
|
||||||
|
image: "/images/snake.gif",
|
||||||
|
imageGallery: null,
|
||||||
|
url: "https://github.com/quaxlyqueen/2410-Snake",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Battery Monitor",
|
||||||
|
description:
|
||||||
|
"A battery monitor, written in C with a GUI written in Python. Utilizes the acpi Unix command to gather battery information. Implemented features incldue:",
|
||||||
|
featureList: [
|
||||||
|
"embed Unix commands in C to get the date, time, battery percentage, and battery status",
|
||||||
|
"basic file I/O to store historical battery data",
|
||||||
|
"daemonize to run as a background process",
|
||||||
|
"script to install as a SystemD service",
|
||||||
|
"basic Python GUI in TKinter to provide graph of data",
|
||||||
|
],
|
||||||
|
image: "/images/battery-mon.png",
|
||||||
|
imageGallery: null,
|
||||||
|
url: "https://github.com/quaxlyqueen/battery-mon",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "D&D Character Builder",
|
||||||
|
description:
|
||||||
|
"A Dungeons and Dragons character builder, following the 5th edition rules and creation process. A collaborative project creating a GUI in Java with Swing. Features include:",
|
||||||
|
featureList: [
|
||||||
|
"serialization of character data into custom filetype",
|
||||||
|
"global styling and custom font import",
|
||||||
|
"button hover effects",
|
||||||
|
],
|
||||||
|
image: "/images/dnd.png",
|
||||||
|
imageGallery: null,
|
||||||
|
url: "https://github.com/quaxlyqueen/dnd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Calculator",
|
||||||
|
description:
|
||||||
|
"A simple and themable calculator written in Python. This uses CustomTKinter for the GUI and the eva CLI package for the actual calculator functionality. Supports MacOS and Linux. Implemented features include:",
|
||||||
|
featureList: [
|
||||||
|
"custom theming read in from a global .theme file",
|
||||||
|
"button hover effects",
|
||||||
|
"keyboard input",
|
||||||
|
],
|
||||||
|
image: "/images/calculator.gif",
|
||||||
|
imageGallery: null,
|
||||||
|
url: "https://github.com/quaxlyqueen/calculator",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const skillData = {
|
||||||
|
languages: [
|
||||||
|
"C & C#",
|
||||||
|
"HTML & CSS",
|
||||||
|
"Go",
|
||||||
|
"Java",
|
||||||
|
"JavaScript & Dart",
|
||||||
|
"Python",
|
||||||
|
],
|
||||||
|
tools: [
|
||||||
|
"Git & GitHub",
|
||||||
|
"Docker",
|
||||||
|
"Flutter & React",
|
||||||
|
"Linux & NeoVim",
|
||||||
|
"Cloudflare",
|
||||||
|
"Microsoft Intune",
|
||||||
|
],
|
||||||
|
other: [
|
||||||
|
"Written Communication",
|
||||||
|
"Conflict Resolution",
|
||||||
|
"Project Management",
|
||||||
|
"Event Planning",
|
||||||
|
"Electronics Repair",
|
||||||
|
"Soldering",
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const jobData = [
|
||||||
|
{
|
||||||
|
company: "SLC Public Library",
|
||||||
|
title: "Technology & Digital Equity Assistant",
|
||||||
|
start: "Aug '23",
|
||||||
|
end: "Present",
|
||||||
|
location: "Salt Lake City, UT",
|
||||||
|
responsibilities: [
|
||||||
|
"Assist library patrons with using technology, on devices such as publicly available PCs, laptops, mobile devices, and more.",
|
||||||
|
"Teach fundamental computer usage skills.",
|
||||||
|
"Expose patrons to the importance of digital security, password management, and two-factor authentication.",
|
||||||
|
"Developing workshop curriculum for Raspberry Pi’s."
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
company: "Trust Lands Admin.",
|
||||||
|
title: "IT Intern",
|
||||||
|
start: "Aug '23",
|
||||||
|
end: "Aug '24",
|
||||||
|
location: "Salt Lake City, UT",
|
||||||
|
responsibilities: [
|
||||||
|
"Orchestrated Microsoft Intune setup and deployment to multiple platforms.",
|
||||||
|
"Streamlined IT equipment inventory process",
|
||||||
|
"Provided training to optimize the usage of hardware and software.",
|
||||||
|
"Troubleshoot and repair hardware and software on a variety of devices.",
|
||||||
|
"Developed automation scripts for use in various parts of the business.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const eduData = [
|
||||||
|
{
|
||||||
|
institution: "Salt Lake Comm. College",
|
||||||
|
degree: "AS Comp Sci",
|
||||||
|
gpa: "3.48 (CS) || 2.87 (Cumulative)",
|
||||||
|
start: "Jan '21",
|
||||||
|
end: "Present",
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<Router>
|
<Router>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route exact path="/" element={<App />} />
|
<Route exact path="/" element={<App projectData={projectData} skillData={skillData} />} />
|
||||||
<Route exact path="/resume" element={<Resume />} />
|
<Route exact path="/resume" element={<Resume jobData={jobData} eduData={eduData} skillData={skillData} />} />
|
||||||
<Route
|
<Route
|
||||||
path="*"
|
path="*"
|
||||||
element={
|
element={
|
||||||
|
|||||||
Reference in New Issue
Block a user