dockerization.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import React from "react";
|
||||
|
||||
/*
|
||||
* An individual Project Card component, generated from project data in /App.jsx. Displays an image/gif
|
||||
* of the project to the left on desktop, and above on mobile, a card. This card is simple, just a header,
|
||||
* some description text, a list of implemented features, and a button to navigate to the GitHub for the
|
||||
* project.
|
||||
*
|
||||
* Managed by /Projects.jsx.
|
||||
* Data by /main.jsx > /App.jsx > /Projects.jsx.
|
||||
*
|
||||
* @param title String
|
||||
* @param description String
|
||||
* @param featureList String[]
|
||||
* @param image String
|
||||
* @param url String
|
||||
*/
|
||||
const ProjectCard = ({
|
||||
title,
|
||||
description,
|
||||
featureList,
|
||||
image,
|
||||
url,
|
||||
}) => {
|
||||
return (
|
||||
<div className="project-card">
|
||||
<div className="img-container">
|
||||
<img src={image} className="shadow" />
|
||||
</div>
|
||||
<div className="project-text-column shadow">
|
||||
<div className="project-text">
|
||||
<h3>{title}</h3>
|
||||
<p>{description}</p>
|
||||
<ul className="feature-list">
|
||||
{featureList.map((item, index) => (
|
||||
<li key={index}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="row">
|
||||
<a className="button" href={url} target="_blank">
|
||||
<div className="button-grid">View on GitHub</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProjectCard;
|
||||
@@ -0,0 +1,51 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
/**
|
||||
* Skill Card component.
|
||||
*
|
||||
* 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 /Home.jsx.
|
||||
* Data by /main.jsx > /App.jsx > /Home.jsx
|
||||
*
|
||||
* @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 list String[], a list of skills
|
||||
* @param isActive boolean, the parent's state tracking if this instance of a skill card is the active (open) one. Only applicable to mobile.
|
||||
* @param onToggle function(), the action the parent component state takes when a skill card header is pressed. Only applicable to mobile.
|
||||
*/
|
||||
const SkillCard = ({ header, symbol, list, isActive, onToggle }) => {
|
||||
const [isMobile, setIsMobile] = useState(window.innerWidth <= 900);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
const mediaQuery = window.matchMedia("(max-width: 900px)");
|
||||
setIsMobile(mediaQuery.matches);
|
||||
};
|
||||
|
||||
handleResize(); // Initial check on mount
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
return () => window.removeEventListener("resize", handleResize);
|
||||
}, []);
|
||||
|
||||
// Display if on desktop (!isMobile) or if Home.jsx determines this to be the currently active component.
|
||||
return (
|
||||
<div className="card shadow">
|
||||
<div className="skill-card-header" onClick={() => onToggle()}>
|
||||
<span className="material-icons skill-symbol">{symbol}</span>
|
||||
<h4>{header}</h4>
|
||||
</div>
|
||||
{(isActive || !isMobile) && (
|
||||
<ul>
|
||||
{list.map((item, index) => (
|
||||
<li key={index}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SkillCard;
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from "react";
|
||||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import { Mousewheel, Pagination } from "swiper/modules";
|
||||
|
||||
import "swiper/css";
|
||||
import "swiper/css/pagination";
|
||||
|
||||
/*
|
||||
* For my portfolio, this is the wrapper in which all other content is displayed. Every component is
|
||||
* a child of the VerticalSlider, excluding the Resume page (for now?).
|
||||
*
|
||||
* Utilizes swiperjs, see https://swiperjs.com/ for documentation.
|
||||
*
|
||||
* @param slides ReactComponent[], an array of pages or "slides" to display in a vertical slider.
|
||||
*/
|
||||
const VerticalSlider = ({ slides }) => {
|
||||
// Mousewheel is for scrolling effect. Pagination is for "bullets" to indicate active and inactive slides. Pagination
|
||||
// clickable allows for going to the corresponding page or "slide".
|
||||
return (
|
||||
<>
|
||||
<Swiper
|
||||
modules={[Mousewheel, Pagination]}
|
||||
direction={"vertical"}
|
||||
speed={800}
|
||||
loop={false}
|
||||
pagination={{
|
||||
clickable: true,
|
||||
}}
|
||||
mousewheel={{
|
||||
thresholdDelta: 50,
|
||||
sensitivity: 1,
|
||||
}}
|
||||
>
|
||||
{slides.map((slide, index) => (
|
||||
<SwiperSlide key={index}>
|
||||
{<div className="slide-container">{slide}</div>}
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default VerticalSlider;
|
||||
Reference in New Issue
Block a user