Implemented primary section consisting of key information, including collapsible skill cards.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
import React from "react";
|
||||
|
||||
export default function About() {
|
||||
return <p>TODO: About()</p>;
|
||||
}
|
||||
+45
-17
@@ -1,22 +1,50 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import VerticalSlider from "./components/VerticalSlider";
|
||||
import "./styles.css";
|
||||
import Primary from "./Primary";
|
||||
import Skills from "./Skills";
|
||||
import Projects from "./Projects";
|
||||
import Contact from "./Contact";
|
||||
import About from "./About";
|
||||
import ProjectCard from "./components/ProjectCard";
|
||||
import "./main.css";
|
||||
|
||||
/**
|
||||
* TODO: Read in data from a plain text file for easier editing in the future.
|
||||
*/
|
||||
export default function App() {
|
||||
const data = [
|
||||
{
|
||||
title: "Test Header",
|
||||
description: "A description of some length. Lorem ipsum this shit.",
|
||||
color: "purple",
|
||||
image: "/images/landscape.jpg",
|
||||
alt: "A pretty background.",
|
||||
},
|
||||
{
|
||||
title: "Another one",
|
||||
description: "A description of some length. Lorem ipsum this shit.",
|
||||
color: "purple",
|
||||
image: "/images/landscape.jpg",
|
||||
alt: "A pretty background.",
|
||||
},
|
||||
const cards = [<ProjectCard />, <ProjectCard />, <ProjectCard />];
|
||||
|
||||
const skills = {
|
||||
languages: ["Java", "JavaScript", "Go", "Dart", "Python", "C#"],
|
||||
tools: [
|
||||
"Git & GitHub",
|
||||
"Docker & Kubernetes",
|
||||
"Flutter",
|
||||
"React",
|
||||
"Linux",
|
||||
"Microsoft Intune",
|
||||
],
|
||||
other: [
|
||||
"Written Communication",
|
||||
"Conflict Resolution",
|
||||
"Project Management",
|
||||
"Event Planning",
|
||||
"Electronics Repair",
|
||||
"Soldering",
|
||||
],
|
||||
};
|
||||
|
||||
const slides = [
|
||||
<Primary
|
||||
primaryText="Hi, I'm Josh Ashton."
|
||||
secondaryText="Junior full-stack developer."
|
||||
callToAction="Here's my resume."
|
||||
image="/images/profile.jpg"
|
||||
skills={skills}
|
||||
/>,
|
||||
<Projects cards={cards} />,
|
||||
<Contact />,
|
||||
<About />,
|
||||
];
|
||||
return <VerticalSlider slideData={data} />;
|
||||
return <VerticalSlider slides={slides} />;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from "react";
|
||||
|
||||
export default function Contact() {
|
||||
return <p>TODO: Contact()</p>;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// TODO: Replace h4 callToAction with a button callToAction.
|
||||
import React, { useState } from "react";
|
||||
import SkillCard from "./components/SkillCard";
|
||||
|
||||
export default function Primary({
|
||||
primaryText,
|
||||
secondaryText,
|
||||
callToAction,
|
||||
image,
|
||||
skills,
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<div id="primary">
|
||||
<div id="header">
|
||||
<div id="header-text">
|
||||
<h1>{primaryText}</h1>
|
||||
<h3>{secondaryText}</h3>
|
||||
<h4>{callToAction}</h4>
|
||||
</div>
|
||||
<div id="header-image">
|
||||
<img id="profile" src={image} />
|
||||
</div>
|
||||
</div>
|
||||
<div id="skills-section">
|
||||
<div className="cards">
|
||||
<SkillCard
|
||||
header="Languages"
|
||||
symbol="code"
|
||||
list={skills.languages}
|
||||
initState={true}
|
||||
/>
|
||||
<SkillCard
|
||||
header="Tools"
|
||||
symbol="terminal"
|
||||
list={skills.tools}
|
||||
initState={false}
|
||||
/>
|
||||
<SkillCard
|
||||
header="Other"
|
||||
symbol="hub"
|
||||
list={skills.other}
|
||||
initState={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span className="material-icons down-indicator">
|
||||
keyboard_double_arrow_down
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from "react";
|
||||
|
||||
export default function Projects() {
|
||||
return <p>TODO: Projects()</p>;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from "react";
|
||||
|
||||
export default function Skills({ skills }) {
|
||||
const languages = skills.languages;
|
||||
const tools = skills.tools;
|
||||
const other = skills.other;
|
||||
return <></>;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import React, { createContext, useState } from "react";
|
||||
|
||||
const AccordionContext = createContext();
|
||||
|
||||
export const AccordionProvider = ({ children }) => {
|
||||
const [expandedCardId, setExpandedCardId] = useState(null);
|
||||
|
||||
const handleAccordionClick = (cardId) => {
|
||||
setExpandedCardId(cardId === expandedCardId ? null : cardId);
|
||||
};
|
||||
|
||||
return (
|
||||
<AccordionContext.Provider value={{ expandedCardId, handleAccordionClick }}>
|
||||
{children}
|
||||
</AccordionContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccordionContext;
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from "react";
|
||||
|
||||
export default function ProjectCard() {
|
||||
return <p>TODO: Need to implement ProjectCard</p>;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
export default function SkillCard({ header, symbol, list, initState }) {
|
||||
const [isExpanded, setIsExpanded] = useState(initState); // Initial state
|
||||
|
||||
const toggleExpansion = () => {
|
||||
setIsExpanded(!isExpanded);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
<div className="skill-section-header" onClick={toggleExpansion}>
|
||||
<span className="material-icons skill-symbol">{symbol}</span>
|
||||
<h3>{header}</h3>
|
||||
</div>
|
||||
{isExpanded && (
|
||||
<ul>
|
||||
{list.map((item) => (
|
||||
<li>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,16 +4,16 @@ import { Mousewheel, Pagination } from "swiper/modules";
|
||||
|
||||
import "swiper/css";
|
||||
import "swiper/css/pagination";
|
||||
import "../styles.css";
|
||||
import "../main.css";
|
||||
|
||||
export default function VerticalSlider({ slideData }) {
|
||||
export default function VerticalSlider({ slides }) {
|
||||
return (
|
||||
<>
|
||||
<Swiper
|
||||
modules={[Mousewheel, Pagination]}
|
||||
direction={"vertical"}
|
||||
speed={800}
|
||||
loop={true}
|
||||
loop={false}
|
||||
pagination={{
|
||||
clickable: true,
|
||||
}}
|
||||
@@ -22,23 +22,9 @@ export default function VerticalSlider({ slideData }) {
|
||||
sensitivity: 1,
|
||||
}}
|
||||
>
|
||||
{slideData.map((slide, index) => (
|
||||
{slides.map((slide, index) => (
|
||||
<SwiperSlide key={index}>
|
||||
{({ isActive }) => (
|
||||
<div className="slide-container">
|
||||
<div className="info">
|
||||
<h1 data-color={slide.color}>{slide.title}</h1>
|
||||
<p>{slide.description}</p>
|
||||
</div>
|
||||
<div className="item">
|
||||
<div
|
||||
className={`circle ${isActive ? "animated-circle" : ""}`}
|
||||
data-item={slide.color}
|
||||
></div>
|
||||
<img src={slide.image} alt={slide.alt} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{({ isActive }) => <div className="slide-container">{slide}</div>}
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
|
||||
+429
@@ -0,0 +1,429 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap");
|
||||
|
||||
/*
|
||||
#EBD2FF
|
||||
#c69bca
|
||||
#9e75a8
|
||||
#4a245e
|
||||
*/
|
||||
|
||||
:root {
|
||||
--width: 480px;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: "Lato", sans-serif;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
background: #222;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
#84509f 0%,
|
||||
#5e3276 39%,
|
||||
hsl(279deg 62% 19%) 61%,
|
||||
hsl(279deg 94% 7%) 100%
|
||||
);
|
||||
background-size:
|
||||
300% 100%,
|
||||
cover;
|
||||
animation: background-fade 4s linear infinite;
|
||||
animation-direction: alternate;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.swiper-pagination-bullet {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-color: #f9f2ff;
|
||||
border-radius: 50%;
|
||||
transition: all 0.6s ease-in-out;
|
||||
}
|
||||
|
||||
.swiper-pagination-bullet-active {
|
||||
height: 36px;
|
||||
background-color: #ebd2ff;
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
#primary {
|
||||
display: grid;
|
||||
height: 100vh;
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: 40% 50% 10%;
|
||||
column-gap: 1vh;
|
||||
}
|
||||
|
||||
#header {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 60% 35%;
|
||||
grid-template-rows: 100%;
|
||||
column-gap: 2vw;
|
||||
}
|
||||
|
||||
#header-text {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-left: 120px;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#header-text h1 {
|
||||
font-size: clamp(4.25rem, 5.5vw, 10rem);
|
||||
font-weight: 600;
|
||||
letter-spacing: 2px;
|
||||
width: max-content;
|
||||
margin-bottom: 32px;
|
||||
opacity: 0;
|
||||
color: #ebd2ff;
|
||||
}
|
||||
|
||||
#header-text h3,
|
||||
#header-text h4 {
|
||||
color: #ebd2ff;
|
||||
font-weight: 300;
|
||||
line-height: 1.5;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#header-text h3 {
|
||||
font-size: clamp(1.5rem, 3vw, 3rem);
|
||||
}
|
||||
#header-text h4 {
|
||||
font-size: clamp(1rem, 1.5vw, 1.25rem);
|
||||
}
|
||||
|
||||
.swiper-slide-active #header-text {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.swiper-slide-active #header-text h1,
|
||||
.swiper-slide-active #header-text h3,
|
||||
.swiper-slide-active #header-text h4 {
|
||||
animation: moveDown 0.8s ease-in forwards;
|
||||
}
|
||||
|
||||
.swiper-slide-active #header-text h1 {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.swiper-slide-active #header-text h3 {
|
||||
animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.swiper-slide-active #header-text h4 {
|
||||
animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
#header-image {
|
||||
height: 40vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--width);
|
||||
aspect-ratio: 1/1;
|
||||
margin: 0 auto;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#header-image img {
|
||||
display: block;
|
||||
width: calc(var(--width) / 2);
|
||||
filter: drop-shadow(5px 6px 5px rgba(36, 36, 42, 0.5));
|
||||
user-select: none;
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#header-image img {
|
||||
animation: imgMoveDown 0.8s ease-in forwards 0.2s;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-variation-settings:
|
||||
"FILL" 0,
|
||||
"wght" 200,
|
||||
"GRAD" 0,
|
||||
"opsz" 24;
|
||||
font-size: 5vw;
|
||||
color: #ebd2ff;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#skills-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#skills-section h2 {
|
||||
font-size: clamp(3.25rem, 4.5vw, 8rem);
|
||||
color: #ebd2ff;
|
||||
opacity: 0;
|
||||
padding-bottom: 36px;
|
||||
}
|
||||
|
||||
.cards {
|
||||
display: grid;
|
||||
grid-template-columns: 30% 30% 30%;
|
||||
grid-template-rows: 100%;
|
||||
column-gap: 2.25vw;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
background-color: #ebd2ff;
|
||||
border-radius: 20px;
|
||||
width: 20vw;
|
||||
box-shadow:
|
||||
0 13px 27px -5px hsla(240, 30.1%, 28%, 0.25),
|
||||
0 8px 16px -8px hsla(0, 0%, 0%, 0.3),
|
||||
0 -6px 16px -6px hsla(0, 0%, 0%, 0.03);
|
||||
}
|
||||
|
||||
.card .skill-section-header {
|
||||
display: grid;
|
||||
grid-template-columns: 20% 60%;
|
||||
grid-template-rows: 100%;
|
||||
column-gap: 1vw;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
|
||||
padding: 2vw;
|
||||
margin: 0;
|
||||
background-color: #4a245e;
|
||||
border-radius: 18px 18px 0 0;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card .skill-section-header .skill-symbol {
|
||||
font-variation-settings:
|
||||
"FILL" 0,
|
||||
"wght" 200,
|
||||
"GRAD" 0,
|
||||
"opsz" 24;
|
||||
font-size: 5vw;
|
||||
height: 5vh;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.card .skill-section-header h3 {
|
||||
font-size: clamp(1rem, 2vw, 3rem);
|
||||
color: #ebd2ff;
|
||||
}
|
||||
|
||||
.card ul {
|
||||
padding: 1vw;
|
||||
}
|
||||
|
||||
.card ul li {
|
||||
list-style: none;
|
||||
font-size: clamp(1rem, 1.25vw, 1.5rem);
|
||||
color: #4a245e;
|
||||
}
|
||||
|
||||
.swiper-slide-active #skills-section .cards .card {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.swiper-slide-active #skills-section h2,
|
||||
.swiper-slide-active #skills-section .card {
|
||||
animation: moveCardsDown 0.8s ease-in forwards;
|
||||
}
|
||||
|
||||
.swiper-slide-active #skills-section .card {
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
.down-indicator {
|
||||
opacity: 0;
|
||||
animation: moveDown 0.8s ease-in forwards;
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
/**Animations**/
|
||||
@keyframes background-fade {
|
||||
from {
|
||||
background-position: right, center;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes moveDown {
|
||||
0% {
|
||||
transform: translateY(-20px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes moveCardsDown {
|
||||
0% {
|
||||
transform: translateY(-40px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes imgMoveDown {
|
||||
0% {
|
||||
transform: translateY(calc(var(--width) / -5));
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**Responsiveness**/
|
||||
@media (max-width: 1250px) {
|
||||
#header-text {
|
||||
padding-left: 90px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1075px) {
|
||||
:root {
|
||||
--width: 400px;
|
||||
}
|
||||
|
||||
.swiper-slide .slide-container {
|
||||
column-gap: 20px;
|
||||
}
|
||||
|
||||
#header-text {
|
||||
padding-left: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 990px) {
|
||||
:root {
|
||||
--width: 360px;
|
||||
}
|
||||
|
||||
#header-text {
|
||||
padding-left: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 790px) {
|
||||
#primary {
|
||||
display: grid;
|
||||
grid-template-rows: 50% 40% 10%;
|
||||
grid-template-columns: 100%;
|
||||
}
|
||||
|
||||
#header {
|
||||
grid-template-columns: 60% 40%;
|
||||
}
|
||||
|
||||
#header-text {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#header-text h1 {
|
||||
font-size: clamp(2.5rem, 2.75vw, 3rem);
|
||||
}
|
||||
|
||||
#header-image {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
#skills-section .card .skill-section-header {
|
||||
border-radius: 18px 18px 18px 18px;
|
||||
}
|
||||
|
||||
#skills-section h2 {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.cards {
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: 30% 30% 30%;
|
||||
column-gap: 0;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 50vw;
|
||||
margin: 1vw;
|
||||
}
|
||||
|
||||
.card .skill-section-header h3 {
|
||||
font-size: clamp(1.5rem, 2vw, 2.5rem);
|
||||
}
|
||||
|
||||
#header-text h1 {
|
||||
margin-bottom: 16px;
|
||||
width: unset;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.swiper-pagination-bullet {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.swiper-pagination-bullet-active {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.material-symbols-outlined {
|
||||
font-size: 10vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 485px) {
|
||||
:root {
|
||||
--width: 280px;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -175,7 +175,7 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.swiper-paginatino-bullet {
|
||||
.swiper-pagination-bullet {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-color: #7e7e7e;
|
||||
|
||||
Reference in New Issue
Block a user