diff --git a/README.md b/README.md index 276bd9a2..84ae04fd 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,6 @@ Week 1: 17/12/24 - 23/12/24 (Planning for the future) - [ ] Script to easily add new projects (components). - [x] Embeddable PDFs (research phase). -Bug Fixes: - -- [x] Breathing animation of background gradient stopped. -- [x] Add state to skill accordions for mobile. -- [x] Alignment of project card on mobile. -- [ ] Profile picture animation is slightly cutoff on mobile. - Week 2: 24/12/24 - 30/12/24 (Adding key information) - [x] Resume page (HTML and PDF options). @@ -30,7 +23,7 @@ Week 2: 24/12/24 - 30/12/24 (Adding key information) - [ ] Meet required pages and content - [ ] Embed PDF course reflections/signature assignments. - [x] Contact page. - - [ ] Implement MailTrap for sending me automated emails when there is a contact form submission. + - [x] Implement MailTrap for sending me automated emails when there is a contact form submission. Week 3: 31/12/24 - 6/12/24 @@ -42,3 +35,39 @@ Week 3: 31/12/24 - 6/12/24 - [ ] Separate user for self-hosting, with reduced permissions. - [ ] Dockerize - [ ] Blog page (stretch goal). + +Major Bugs (UI, UX, or Functionality): + +- [x] Breathing animation of background gradient stopped. +- [x] Add state to skill accordions for mobile. +- [x] Alignment of project card on mobile. +- [x] PDF viewer width is constant, doesn't respond to resizing (or setting the width in CSS). +- [ ] More prominent slide indicator for projects (or n/10 counter, or some similar solution). + +Features + +- [x] Refactor and reorder the HTML & CSS. +- [x] Template HTML blocks for repeated components. +- [x] Resume page (HTML and PDF options). +- [x] Contact page. +- [x] Convert SLCC e-portfolio to my own website +- [ ] Security: + - [ ] Separate user for self-hosting, with reduced permissions. + - [ ] Dockerize +- [ ] Proper 404 page + +Stretch Goals: + +- [ ] Blog page (stretch goal). +- [ ] Read in data for portfolio from a DB or preferably a plain text files. +- [ ] Script to easily add new projects. +- [ ] Demo's of various projects. (embed Java Swing app or Flutter app directly into portfolio). + +Refactoring: + +- [ ] Rewrite CSS into components/modules + +Minor Bugs: + +- [ ] Contact form submission centers entire section. +- [ ] Profile picture animation is slightly cutoff on mobile. diff --git a/public/slcc/Portrait of My Writing Life.pdf b/public/slcc/Portrait of My Writing Life.pdf new file mode 100644 index 00000000..3a922df9 Binary files /dev/null and b/public/slcc/Portrait of My Writing Life.pdf differ diff --git a/public/slcc/Public Policy Project.pdf b/public/slcc/Public Policy Project.pdf new file mode 100644 index 00000000..c9784a05 Binary files /dev/null and b/public/slcc/Public Policy Project.pdf differ diff --git a/public/slcc/Rhetorical Analysis.pdf b/public/slcc/Rhetorical Analysis.pdf new file mode 100644 index 00000000..45a2d158 Binary files /dev/null and b/public/slcc/Rhetorical Analysis.pdf differ diff --git a/public/slcc/Sensory Paper.pdf b/public/slcc/Sensory Paper.pdf new file mode 100644 index 00000000..fdd83e49 Binary files /dev/null and b/public/slcc/Sensory Paper.pdf differ diff --git a/public/slcc/Unit 1 Analytical Essay.pdf b/public/slcc/Unit 1 Analytical Essay.pdf new file mode 100644 index 00000000..9a3e27a6 Binary files /dev/null and b/public/slcc/Unit 1 Analytical Essay.pdf differ diff --git a/public/slcc/Unit 2 Analytical Essay.pdf b/public/slcc/Unit 2 Analytical Essay.pdf new file mode 100644 index 00000000..28f7e897 Binary files /dev/null and b/public/slcc/Unit 2 Analytical Essay.pdf differ diff --git a/public/slcc/Unit 3 Analytical Essay.pdf b/public/slcc/Unit 3 Analytical Essay.pdf new file mode 100644 index 00000000..c2ae8aa0 Binary files /dev/null and b/public/slcc/Unit 3 Analytical Essay.pdf differ diff --git a/src/App.jsx b/src/App.jsx index 96af51b7..c0a6a1f3 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import VerticalSlider from "./components/VerticalSlider"; -import Primary from "./Primary"; +import Home from "./Home"; import Projects from "./Projects"; import Contact from "./Contact"; import "./main.css"; @@ -73,7 +73,7 @@ export default function App() { }; const slides = [ - +
+
+
+ +
+
+
+

{primaryText}

+

{secondaryText}

+ +
Access my resume
+
+
+
+
+ {skills.languages !== null ? ( +
+
+ setActiveCardIndex(0)} + /> + setActiveCardIndex(1)} + /> + setActiveCardIndex(2)} + /> +
+
+ ) : ( +

Something here

+ )} + + keyboard_double_arrow_down + +
+ + ); +} diff --git a/src/Primary.jsx b/src/Primary.jsx deleted file mode 100644 index 6b0e707a..00000000 --- a/src/Primary.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import React, { useState } from "react"; -import SkillCard from "./components/SkillCard"; - -export default function Primary({ primaryText, secondaryText, image, skills }) { - const [activeCardIndex, setActiveCardIndex] = useState(0); - return ( - <> -
- -
-
- setActiveCardIndex(0)} - /> - setActiveCardIndex(1)} - /> - setActiveCardIndex(2)} - /> -
-
- - keyboard_double_arrow_down - -
- - ); -} diff --git a/src/Slcc.jsx b/src/Slcc.jsx new file mode 100644 index 00000000..24c4ccef --- /dev/null +++ b/src/Slcc.jsx @@ -0,0 +1,28 @@ +import React, { useState } from "react"; +import SlccCourseView from "./SlccCourseView.jsx"; +import SlccNav from "./components/SlccNav.jsx"; +import SlccSplash from "./components/SlccSplash.jsx"; +import SlccGoals from "./components/SlccGoals.jsx"; + +export default function Slcc() { + var currentPageComponent; + const pages = [, , ]; + const [currentPage, setCurrentPage] = useState(0); + + if (currentPage === 0) { + currentPageComponent = pages[0]; + } else if (currentPage === 1) { + currentPageComponent = pages[1]; + } else if (currentPage === 2) { + currentPageComponent = pages[2]; + } + + return ( + <> +
+ +
+ {currentPageComponent} + + ); +} diff --git a/src/SlccCourseView.jsx b/src/SlccCourseView.jsx new file mode 100644 index 00000000..ffdb8433 --- /dev/null +++ b/src/SlccCourseView.jsx @@ -0,0 +1,88 @@ +import React, { useState } from "react"; +import SlccCoursePage from "./components/SlccCoursePage.jsx"; + +export default function SlccCourseView() { + const courseData = [ + { + name: "POLS 1100", + header: "POLS 1100 - Intro. to US Government and Politics", + sections: [ + { + header: "Overview", + text: "I thoroughly enjoyed the assignments in POLS 1100, as I have always struggled to relay my thoughts effectively to others, and writing my political thoughts in this course seems to be a natural outlet for my internal dialogue. This course, paired with ENGL 1010, has inspired me to pursue writing -not as a career, but for my own enjoyment as I have truly come to enjoy the writing I have done over the Summer 2021 semester when I took these courses.", + pathToPdf: null, + }, + { + header: "Public Policy Project", + text: "On this signature assignment, I wrote a research paper broken into four parts: defining the problems caused by unsafe storage of firearms, criteria to determine the efficacy of a policy, three possible policy solutions, and in-depth analysis on my chosen public policy solution, creating a tax credit for safe storage options. This project challenged me to think critically about the existing positions that I have regarding safe firearm storage, and to communicate those thoughts with data and clear speech. Part of why I chose this topic was because of my experience as the Political Director for March for our Lives Arizona, a youth-led gun violence prevention organization in which I advocated for the principles and policy agenda I write about. I enjoyed this assignment fully, and it acted as part of the push towards my own personal enjoyment of writing when paired with the Rhetorical Analysis Essay for ENGL 1010.", + pathToPdf: "/slcc/Public Policy Project.pdf", + }, + { + header: "The First Amendment", + text: "In this essay, I examined how and why our First Amendment is the most critical foundation to the United States. These three essays allowed me to confront some big issues in our formal and informal political systems, that are unfortunately rarely mentioned in our political discourse. The thinking that I've had on these issues has largely remained the same but pushed towards writing to more clearly convey my thoughts and opinions. These essays in particular played an enormous role in kickstarting my long-dead love of writing and changed my perspective to approach life looking to learn.", + pathToPdf: "/slcc/Unit 1 Analytical Essay.pdf", + }, + { + header: "The Danger of Hyper-Partisanship", + text: "Here, I investigated the Founder's Vision for the United States Congress -and how today we fail to meet that standard. These three essays allowed me to confront some big issues in our formal and informal political systems, that are unfortunately rarely mentioned in our political discourse. The thinking that I've had on these issues has largely remained the same but pushed towards writing to more clearly convey my thoughts and opinions. These essays in particular played an enormous role in kickstarting my long-dead love of writing and changed my perspective to approach life looking to learn.", + pathToPdf: "/slcc/Unit 2 Analytical Essay.pdf", + }, + { + header: "Big Tech's Bubble Effect on Politics", + text: "In this paper, I scrutinized the role Big Tech has in our politics, particularly how the content we consume is designed to reinforce our existing beliefs. These three essays allowed me to confront some big issues in our formal and informal political systems, that are unfortunately rarely mentioned in our political discourse. The thinking that I've had on these issues has largely remained the same but pushed towards writing to more clearly convey my thoughts and opinions. These essays in particular played an enormous role in kickstarting my long-dead love of writing and changed my perspective to approach life looking to learn.", + pathToPdf: "/slcc/Unit 3 Analytical Essay.pdf", + }, + ], + }, + { + name: "ENGL 1010", + header: "ENGL 1010 - Introduction to Writing", + sections: [ + { + header: "Rhetorical Analysis", + text: "This signature assignment had a focus on examining the rhetorical devices authors use, and how they use those devices, to determine the effectiveness of their voice and argument.", + pathToPdf: "/slcc/Rhetorical Analysis.pdf", + }, + { + header: "Portrait of My Writing Life", + text: "This assignment acts as a reflection of my writing over the Summer 2021 semester, where I've begun, and where I am now. I wrote about the two considerations that were talked about every day in class: audience and purpose, and practice.", + pathToPdf: "/slcc/Portrait of My Writing Life.pdf", + }, + { + header: "Sensory Paper", + text: "This introductory essay had the task of writing a description of 5 senses in as much detail as possible. This essay in particular was a challenge for me, as I am unfamiliar and unpracticed with writing with sensory details.", + pathToPdf: "/slcc/Sensory Paper.pdf", + }, + ], + }, + ]; + + const [selectedCourse, setSelectedCourse] = useState(0); + + const handleCourseSelect = (index) => { + setSelectedCourse(index); + }; + + return ( + <> +
+
+
+ {courseData.map((course, index) => ( +
handleCourseSelect(index)} + > + {course.name} +
+ ))} +
+
+
+ {} +
+
+ + ); +} diff --git a/src/components/PdfViewer.jsx b/src/components/PdfViewer.jsx index 57b494c6..b6330b12 100644 --- a/src/components/PdfViewer.jsx +++ b/src/components/PdfViewer.jsx @@ -18,31 +18,31 @@ export default function PdfViewer({ file }) { } function next() { - if (pageNumber < numPages - 1) { + if (pageNumber < numPages) { setPageNumber(pageNumber + 1); } } - console.log("numPages: " + numPages); - console.log("pageNumber: " + pageNumber); - return ( <>
- { setNumPages(numPagesInPdf); }} + className="pdf-document" > - +
+ + +
); diff --git a/src/components/SlccCoursePage.jsx b/src/components/SlccCoursePage.jsx new file mode 100644 index 00000000..0db15f93 --- /dev/null +++ b/src/components/SlccCoursePage.jsx @@ -0,0 +1,32 @@ +import React, { useRef, useEffect } from "react"; +import { Swiper, SwiperSlide } from "swiper/react"; +import { Navigation } from "swiper/modules"; +import SlccCourseSection from "./SlccCourseSection"; + +// Import Swiper styles +import "swiper/css"; +import "swiper/css/navigation"; + +export default function SlccCoursePage({ course }) { + return ( + <> +

{course.header}

+ + {course.sections.map((section, index) => ( + + + + ))} + + + ); +} diff --git a/src/components/SlccCourseSection.jsx b/src/components/SlccCourseSection.jsx new file mode 100644 index 00000000..4921b5bf --- /dev/null +++ b/src/components/SlccCourseSection.jsx @@ -0,0 +1,16 @@ +import React from "react"; +import PdfViewer from "./PdfViewer"; + +export default function SlccCourseSection({ header, text, pathToPdf }) { + return ( + <> +
+
+

{header}

+

{text}

+
+ {pathToPdf !== null && }{" "} +
+ + ); +} diff --git a/src/components/SlccGoals.jsx b/src/components/SlccGoals.jsx new file mode 100644 index 00000000..651e9f0a --- /dev/null +++ b/src/components/SlccGoals.jsx @@ -0,0 +1,5 @@ +import React from "react"; + +export default function SlccGoals() { + return

Hello cruel world

; +} diff --git a/src/components/SlccNav.jsx b/src/components/SlccNav.jsx new file mode 100644 index 00000000..93fff1b8 --- /dev/null +++ b/src/components/SlccNav.jsx @@ -0,0 +1,56 @@ +import React, { useState } from "react"; + +export default function SlccNav({ currentPage, setCurrentPage }) { + const [isActive, setIsActive] = useState(currentPage); + + function navigateWelcome() { + if (isActive === 0 && currentPage === 0) return; + setIsActive(0); + setCurrentPage(0); + } + + function navigateGoals() { + if (isActive === 1 && currentPage === 1) return; + setIsActive(1); + setCurrentPage(1); + } + + function navigateCourseView() { + if (isActive === 2 && currentPage === 2) return; + setIsActive(2); + setCurrentPage(2); + } + + return ( + <> +
+
    +
  • navigateWelcome()} + > + Welcome +
  • +
  • navigateGoals()} + > + Goals & Outcomes +
  • +
  • navigateCourseView()} + > + Coursework +
  • +
  • viewOutside()} + > + Outside Learning +
  • +
+
+ + ); +} diff --git a/src/components/SlccSplash.jsx b/src/components/SlccSplash.jsx new file mode 100644 index 00000000..af831635 --- /dev/null +++ b/src/components/SlccSplash.jsx @@ -0,0 +1,38 @@ +import React from "react"; + +export default function SlccSplash() { + return ( + <> +
+
+
+ +
+
+
+

Hi, I'm Josh Ashton.

+

+ A Computer Science student at Salt Lake Community College. +

+
+
+
+
+
+

About Me

+

+ A mentor once told me that a Political Science degree is useless + if I want to pursue public policy work. They were absolutely + right. I'm pursuing a degree in Computer Science. The government + needs to be more proactive in regulating new developing + technologies, and I'm hopeful that one day I'll be able to bridge + that gap. Aside from computers, coding, and politics, some of my + other interests are Dungeons & Dragons, video games, backpacking, + and Doctor Who. +

+
+
+
+ + ); +} diff --git a/src/components/VerticalSlider.jsx b/src/components/VerticalSlider.jsx index 71175821..52d0bea7 100644 --- a/src/components/VerticalSlider.jsx +++ b/src/components/VerticalSlider.jsx @@ -4,7 +4,6 @@ import { Mousewheel, Pagination } from "swiper/modules"; import "swiper/css"; import "swiper/css/pagination"; -import "../main.css"; export default function VerticalSlider({ slides }) { return ( diff --git a/src/main.css b/src/main.css index 7c770668..9d9225ca 100644 --- a/src/main.css +++ b/src/main.css @@ -55,6 +55,14 @@ h4 { line-height: 1.5; } +h2 { + font-size: clamp(2rem, 3vw, 4rem); + font-weight: 600; + letter-spacing: 2px; + width: max-content; + color: #ebd2ff; +} + h3 { font-size: clamp(1.5rem, 2vw, 3rem); } @@ -90,6 +98,30 @@ p { 0 -6px 16px -6px hsla(0, 0%, 0%, 0.03); } +.center-column { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; +} + +.center-row { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + text-align: center; +} + +.text-section { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 80%; +} + /**SWIPER PAGES**/ .swiper { width: 100vw; @@ -111,14 +143,16 @@ p { } /**ACTIVE PAGE ANIMATIONS**/ -#header, +.header, #skill-cards, #project-section, #project-cards-section, #contact-section { opacity: 0; } -.swiper-slide-active #header, + +.swiper-slide-active .header, +#slcc-splash .header, .swiper-slide-active #skill-cards, .swiper-slide-active #project-section, .swiper-slide-active #project-cards-section, @@ -126,7 +160,8 @@ p { opacity: 0; } -.swiper-slide-active #header, +.swiper-slide-active .header, +#slcc-splash .header, .swiper-slide-active #skill-cards, .swiper-slide-active #project-section, .swiper-slide-active #project-cards-section, @@ -135,7 +170,8 @@ p { animation: moveDown 0.8s ease-in forwards; } -.swiper-slide-active #header, +.swiper-slide-active .header, +#slcc-splash .header, .swiper-slide-active #project-section, .down-indicator { animation-delay: 0.2s; @@ -168,38 +204,38 @@ p { height: 100vh; grid-template-columns: 100%; grid-template-rows: 40% 40% 10%; - column-gap: 10vh; + column-gap: 5%; } -#header { +.header { width: 100%; overflow: hidden; display: grid; - grid-template-columns: 55% 45%; + grid-template-columns: 30% 60%; grid-template-rows: 100%; } -#header-text { +.header-text { width: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; - padding-left: 120px; text-align: center; } -#header-image { +.header-image { height: 40vh; display: flex; + flex-direction: row; align-items: center; justify-content: center; width: var(--width); margin: 0 auto; } -#header-image img { +.header-image img { width: calc(var(--width) / 2); filter: drop-shadow(5px 6px 5px rgba(36, 36, 42, 0.5)); user-select: none; @@ -449,29 +485,152 @@ p { #resume-section { margin: 2vw; + display: flex; } /**PDF Viewer**/ .pdf-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - max-width: 100%; - height: 70vh; + margin: 0 auto; + width: max-content; + display: grid; + grid-template-columns: 100%; + grid-template-rows: 90% 10%; +} + +.pdf-document { + overflow: hidden; + height: 100%; + width: 50%; + width: max-content; + object-fit: scale-down; +} + +.pdf-buttons { + width: 100%; + display: grid; + grid-template-rows: 100%; + grid-template-columns: 50% 50%; } .pdf-button { + width: 100%; background-color: #ebd2ff; - color: #4a245e; outline: none; border: none; padding: 1vw; - margin: 1vw; + transition-duration: 500ms; } .pdf-button span { + height: 100%; + width: 100%; color: #4a245e; + font-size: clamp(1rem, 2rem, 3rem); + transition-duration: 500ms; +} + +.pdf-button:hover, +.pdf-button:hover span { + background-color: #4a245e; + color: #ebd2ff; +} + +/**SLCC Navigation Bar**/ +.nav { + width: 90%; + margin-top: 3vw; +} + +.nav-list { + display: grid; + grid-template-rows: 100%; + grid-template-columns: 25% 25% 25% 25%; +} + +.nav-item { + border-left: 2px solid #4a245e; + border-right: 2px solid #4a245e; + font-size: clamp(1rem, 1.5vw, 1.25rem); + list-style: none; + padding: 2vw; + color: #4a245e; + background-color: #ebd2ff; + transition-duration: 500ms; +} + +.nav-item:hover, +.nav-item-active { + background-color: #4a245e; + color: #ebd2ff; +} + +/**SLCC Course View**/ +#course-view-container { + height: 70vh; + width: 90%; + display: grid; + grid-template-columns: 10% 80%; + grid-template-rows: 100%; + + margin: 50px auto; +} + +#course-view-selector { + display: grid; + grid-template-rows: repeat(7, 10%); +} + +.course-nav-selector { + border: 2px solid #4a245e; + background-color: #ebd2ff; + color: #4a245e; + height: 100%; + transition-duration: 500ms; +} + +.course-nav-selector:hover, +.course-nav-selector-active { + color: #ebd2ff; + background-color: #4a245e; +} + +.course-header { + margin-left: 2vw; +} + +.course-section { + margin: 0 auto; + width: 90%; + display: grid; + grid-template-columns: 47.5% 47.5%; + column-gap: 5%; +} + +.course-section-text { + width: 100%; +} + +.course-page-slider { + width: 100%; + height: max-content; +} + +.swiper-button-prev, +.swiper-rtl .swiper-button-next { + color: #ebd2ff !important; +} + +.swiper-button-next, +.swiper-rtl .swiper-button-prev { + color: #ebd2ff !important; +} + +.swiper-button-prev.swiper-button-disabled { + color: #ebd2ff !important; +} + +.swiper-button-next.swiper-button-disabled { + color: #ebd2ff !important; } /**Animations**/ @@ -546,18 +705,34 @@ p { } @media (max-width: 790px) { - #primary { + #primary, + #slcc-splash { + width: 100%; display: grid; - grid-template-rows: 40% 40% 10%; + grid-template-rows: 50% 50%; grid-template-columns: 100%; } - #header { - grid-template-columns: 60% 40%; + .header { + width: 100%; + + display: grid; + grid-template-columns: 100%; + grid-template-rows: 50% 50%; } - #header-text { - margin: 0; + .header .header-image { + max-height: 20vh; + width: 100%; + + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + } + + .header .header-text { + width: 100%; } h1 { @@ -580,13 +755,6 @@ p { font-size: clamp(0.5rem, 0.8rem, 1rem); } - #header-image { - display: flex; - flex-direction: row; - align-items: center; - justify-content: left; - } - .skill-card-header { border-radius: 18px 18px 18px 18px; } diff --git a/src/main.jsx b/src/main.jsx index c659f026..68f9e91d 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -4,6 +4,7 @@ import { BrowserRouter as Router, Routes, Route } from "react-router"; import App from "./App.jsx"; import Resume from "./Resume.jsx"; import PageNotFound from "./PageNotFound.jsx"; +import Slcc from "./Slcc.jsx"; const container = document.getElementById("app"); const root = createRoot(container); // createRoot(container!) if you use TypeScript @@ -12,6 +13,7 @@ root.render( } /> } /> + } /> } /> ,