mirror of
https://gitea.smigz.com/smiggiddy/odin-codeprojects.git
synced 2024-12-26 14:20:43 -05:00
feat: new components, style, etc
This commit is contained in:
parent
c3184ad970
commit
148d037942
11 changed files with 235 additions and 121 deletions
|
@ -2,9 +2,9 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React</title>
|
||||
<title>CV-Creator</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
:root {
|
||||
--font-size: 16px;
|
||||
--default-border-radius: 0.5rem;
|
||||
|
||||
/* Shadows */
|
||||
--default-shadow: 0 4px 6px hsla(0, 0%, 0%, 0.2);
|
||||
--small-shadow: 0 1px 3px hsla(0, 0%, 0%, 0.2);
|
||||
--large-shadow: 0 15px 35px hsla(0, 0%, 0%, 0.2);
|
||||
--tight-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
||||
--wide-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
|
||||
|
||||
/* Grays */
|
||||
--lightest-gray: 208, 21%, 93%;
|
||||
--lighter-gray: 210, 16%, 76%;
|
||||
--light-gray: 208, 12%, 58%;
|
||||
--dark-gray: 207, 12%, 43%;
|
||||
--darker-gray: 209, 15%, 28%;
|
||||
|
||||
--white-color: 360, 100%, 100%;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: var(--font-size);
|
||||
background: hsl(var(--lightest-gray));
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.resume {
|
||||
min-width: 800px;
|
||||
/* background: gray; */
|
||||
}
|
||||
|
||||
.form {
|
||||
max-width: 450px;
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
.general-info-form {
|
||||
padding: 20px;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: var(--default-border-radius);
|
||||
box-shadow: var(--tight-shadow), var(--wide-shadow);
|
||||
background: hsl(var(--white-color));
|
||||
}
|
||||
|
||||
.basic-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.basic-info p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.basic-info-details {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
|
@ -3,18 +3,21 @@ import GeneralInfoDisplay from "./components/generalInfoDisplay";
|
|||
import EducationInfoDisplay from "./components/educationInfoDisplay";
|
||||
import EducationInfoForm from "./components/educationInfoForm";
|
||||
import ExperienceForm from "./components/experienceForm";
|
||||
import ExperienceDisplay from "./components/experienceDisplay";
|
||||
|
||||
import "./App.css";
|
||||
import { useState } from "react";
|
||||
|
||||
function App() {
|
||||
const [basicInfo, setBasicInfo] = useState({
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
fullName: "Marvin Gaye",
|
||||
phone: "301-240-5555",
|
||||
email: "mgaye@motown.com",
|
||||
location: "Detriot, MI",
|
||||
});
|
||||
const [educationInfo, setEducationInfo] = useState([]);
|
||||
const [editEducation, setEditEducation] = useState(null);
|
||||
const [employmentHistory, setEmploymentHistory] = useState([]);
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
|
@ -26,7 +29,10 @@ function App() {
|
|||
setEditEducation={setEditEducation}
|
||||
editEducation={editEducation}
|
||||
/>
|
||||
<ExperienceForm />
|
||||
<ExperienceForm
|
||||
employmentHistory={employmentHistory}
|
||||
setEmploymentHistory={setEmploymentHistory}
|
||||
/>
|
||||
</div>
|
||||
<div className="resume">
|
||||
<GeneralInfoDisplay basicInfo={basicInfo} />
|
||||
|
@ -35,6 +41,7 @@ function App() {
|
|||
setEditEducation={setEditEducation}
|
||||
setEducationInfo={setEducationInfo}
|
||||
/>
|
||||
<ExperienceDisplay employmentHistory={employmentHistory} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,31 +1,25 @@
|
|||
export default function EducationInfoDisplay(props) {
|
||||
return (
|
||||
<div>
|
||||
{props.educationInfo.length <= 0 ? (
|
||||
<>
|
||||
<p>Add your Education info</p>
|
||||
</>
|
||||
) : (
|
||||
<EducationDisplay
|
||||
educationInfo={props.educationInfo}
|
||||
setEducationInfo={props.setEducationInfo}
|
||||
setEditEducation={props.setEditEducation}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<>
|
||||
<EducationDisplay
|
||||
educationInfo={props.educationInfo}
|
||||
setEducationInfo={props.setEducationInfo}
|
||||
setEditEducation={props.setEditEducation}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function EducationDisplay(props) {
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
{props.educationInfo.map((item) => {
|
||||
return (
|
||||
<div key={item.schoolName} className="education-info">
|
||||
<h2>School: {item.schoolName}</h2>
|
||||
<p>
|
||||
Graduation Date: {item.graduationDate + " "}
|
||||
Field of Study: {item.fieldOfStudy}
|
||||
Graduation: {item.graduationDate + " "}
|
||||
Degree: {item.fieldOfStudy}
|
||||
<button onClick={() => props.setEditEducation(item)}>edit</button>
|
||||
<button
|
||||
onClick={() =>
|
||||
|
@ -42,7 +36,7 @@ function EducationDisplay(props) {
|
|||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { useState, useEffect } from "react";
|
||||
|
||||
export default function EducationInfoForm(props) {
|
||||
// const [schools, setSchools] = useState([]);
|
||||
const [educationItemActive, setEducationItemActive] = useState(false);
|
||||
// const [editSchool, setEditSchool] = useState(null);
|
||||
|
||||
return (
|
||||
<div className="education-info section">
|
||||
|
@ -50,15 +48,12 @@ function EducationForm({
|
|||
}, [editSchool]);
|
||||
|
||||
let schoolId = editSchool
|
||||
? educationInfo.findIndex(
|
||||
(school) => school.schoolName === editSchool.schoolName,
|
||||
)
|
||||
? educationInfo.findIndex((school) => school.id === editSchool.id)
|
||||
: null;
|
||||
|
||||
const contactFormStyle = {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "30vw",
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -68,19 +63,19 @@ function EducationForm({
|
|||
<form action="" style={contactFormStyle}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="School Name"
|
||||
placeholder="Enter university/school"
|
||||
value={schoolName}
|
||||
onChange={(e) => setSchoolName(e.target.value)}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Graduation Date"
|
||||
placeholder="Enter graduation date"
|
||||
value={graduationDate}
|
||||
onChange={(e) => setGraduationDate(e.target.value)}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Field of Study"
|
||||
placeholder="Enter degree/field of study"
|
||||
value={fieldOfStudy}
|
||||
onChange={(e) => setFieldOfStudy(e.target.value)}
|
||||
/>
|
||||
|
@ -103,6 +98,7 @@ function EducationForm({
|
|||
schoolName: schoolName,
|
||||
fieldOfStudy: fieldOfStudy,
|
||||
graduationDate: graduationDate,
|
||||
id: crypto.randomUUID(),
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
@ -120,6 +116,7 @@ function EducationForm({
|
|||
setGraduationDate("");
|
||||
setSchoolName("");
|
||||
setFieldOfStudy("");
|
||||
schoolId = null;
|
||||
}}
|
||||
>
|
||||
Clear
|
||||
|
|
26
cv-project/src/components/experienceDisplay.jsx
Normal file
26
cv-project/src/components/experienceDisplay.jsx
Normal file
|
@ -0,0 +1,26 @@
|
|||
export default function ExperienceDisplay(props) {
|
||||
return (
|
||||
<div className="job-info">
|
||||
<JobList jobs={props.employmentHistory} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function JobList(props) {
|
||||
return (
|
||||
<>
|
||||
{props.jobs.map((item) => {
|
||||
return (
|
||||
<div className="job" key={item.id}>
|
||||
<h2>{item.employer}</h2>
|
||||
<h3>{item.jobTitle}</h3>
|
||||
<p>
|
||||
{item.employmentStart} - {item.employmentEnd}
|
||||
</p>
|
||||
<p>{item.jobDescription}</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1,49 +1,23 @@
|
|||
import { useState } from "react";
|
||||
|
||||
export default function ExperienceForm() {
|
||||
const [jobs, setJobs] = useState([]);
|
||||
export default function ExperienceForm(props) {
|
||||
// const [jobs, setJobs] = useState([]);
|
||||
const [showJobForm, setShowJobForm] = useState(false);
|
||||
|
||||
const mainDivStyle = {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row-reverse",
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="jobs" style={mainDivStyle}>
|
||||
<div className="job-info">
|
||||
<JobList jobs={jobs} />
|
||||
</div>
|
||||
<div className="Job-info-form">
|
||||
<button onClick={() => setShowJobForm(!showJobForm)}>
|
||||
Add Employer Info
|
||||
</button>
|
||||
<JobForm setJobs={setJobs} jobs={jobs} isActive={showJobForm} />
|
||||
</div>
|
||||
<div className="Job-info-form">
|
||||
<button onClick={() => setShowJobForm(!showJobForm)}>
|
||||
Add Employer Info
|
||||
</button>
|
||||
<JobForm
|
||||
setJobs={props.setEmploymentHistory}
|
||||
jobs={props.employmentHistory}
|
||||
isActive={showJobForm}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function JobList(props) {
|
||||
return (
|
||||
<>
|
||||
{props.jobs.map((item) => {
|
||||
return (
|
||||
<div className="job" key={item.id}>
|
||||
<h2>{item.employer}</h2>
|
||||
<h3>{item.jobTitle}</h3>
|
||||
<p>
|
||||
{item.employmentStart} - {item.employmentEnd}
|
||||
</p>
|
||||
<p>{item.jobDescription}</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function JobForm({ isActive, jobs, setJobs }) {
|
||||
const [employer, setEmployer] = useState("");
|
||||
const [jobTitle, setJobTitle] = useState("");
|
||||
|
@ -54,7 +28,6 @@ function JobForm({ isActive, jobs, setJobs }) {
|
|||
const formStyle = {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "30vw",
|
||||
};
|
||||
|
||||
function clear() {
|
||||
|
@ -68,7 +41,8 @@ function JobForm({ isActive, jobs, setJobs }) {
|
|||
function handleSubmit(event, stuff) {
|
||||
event.preventDefault();
|
||||
|
||||
const newJob = { ...stuff };
|
||||
const key = crypto.randomUUID();
|
||||
const newJob = { ...stuff, id: key };
|
||||
|
||||
setJobs([...jobs, newJob]);
|
||||
|
||||
|
|
|
@ -2,17 +2,16 @@ export default function GeneralInfoDisplay(props) {
|
|||
const basicInfo = props.basicInfo;
|
||||
return (
|
||||
<>
|
||||
{
|
||||
basicInfo ?
|
||||
(
|
||||
<div className="basic-info" >
|
||||
<h1>{basicInfo.firstName + " " + basicInfo.lastName}</h1>
|
||||
<p>{basicInfo.email}</p>
|
||||
<p>{basicInfo.phone}</p>
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
{basicInfo ? (
|
||||
<div className="basic-info">
|
||||
<h1>{basicInfo.fullName}</h1>
|
||||
<div className="basic-info-details">
|
||||
<p>{basicInfo.location}</p>
|
||||
<p>{basicInfo.email}</p>
|
||||
<p>{basicInfo.phone}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,68 +1,83 @@
|
|||
import { useState } from "react";
|
||||
import Input from "./input";
|
||||
|
||||
export default function GeneralInfoForm(props) {
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [fullName, setFullName] = useState("");
|
||||
const [location, setLocation] = useState("");
|
||||
const [phone, setPhone] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
|
||||
const contactFormStyle = {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "30vw",
|
||||
};
|
||||
|
||||
const mainStyle = {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="general-info section" style={mainStyle}>
|
||||
<div className="contact-info-form">
|
||||
<>
|
||||
<div className="general-info-form">
|
||||
<form action="">
|
||||
<div style={contactFormStyle}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="First Name"
|
||||
value={firstName}
|
||||
<h2 className="general-info-header">Personal Details</h2>
|
||||
<Input
|
||||
label={true}
|
||||
name="fullName"
|
||||
labelName="Full name"
|
||||
value={fullName}
|
||||
placeholder=""
|
||||
onChange={(e) => {
|
||||
setFirstName(e.target.value)
|
||||
props.setBasicInfo({ ...props.basicInfo, firstName: e.target.value })
|
||||
}
|
||||
}
|
||||
setFullName(e.target.value);
|
||||
props.setBasicInfo({
|
||||
...props.basicInfo,
|
||||
fullName: e.target.value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Last Name"
|
||||
value={lastName}
|
||||
<Input
|
||||
label={true}
|
||||
name="location"
|
||||
labelName="Location"
|
||||
placeholder=""
|
||||
value={location}
|
||||
onChange={(e) => {
|
||||
setLastName(e.target.value)
|
||||
props.setBasicInfo({ ...props.basicInfo, lastName: e.target.value })
|
||||
}} />
|
||||
<input
|
||||
setLocation(e.target.value);
|
||||
props.setBasicInfo({
|
||||
...props.basicInfo,
|
||||
location: e.target.value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Input
|
||||
label={true}
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
name="email"
|
||||
labelName="Email"
|
||||
placeholder=""
|
||||
value={email}
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value)
|
||||
props.setBasicInfo({ ...props.basicInfo, email: e.target.value })
|
||||
}
|
||||
}
|
||||
setEmail(e.target.value);
|
||||
props.setBasicInfo({
|
||||
...props.basicInfo,
|
||||
email: e.target.value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Phone Number"
|
||||
label={true}
|
||||
labelName="Phone"
|
||||
placeholder=""
|
||||
value={phone}
|
||||
onChange={(e) => {
|
||||
setPhone(e.target.value)
|
||||
props.setBasicInfo({ ...props.basicInfo, phone: e.target.value })
|
||||
setPhone(e.target.value);
|
||||
props.setBasicInfo({
|
||||
...props.basicInfo,
|
||||
phone: e.target.value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
19
cv-project/src/components/input.jsx
Normal file
19
cv-project/src/components/input.jsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import "../styles/input.css";
|
||||
|
||||
export default function Input(props) {
|
||||
return (
|
||||
<div className="input">
|
||||
{props.label ? (
|
||||
<label htmlFor={props.name}>{props.labelName}</label>
|
||||
) : null}
|
||||
<input
|
||||
name={props.name}
|
||||
id={props.name}
|
||||
type={props.type}
|
||||
value={props.value}
|
||||
onChange={props.onChange}
|
||||
placeholder={props.placeholder}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
15
cv-project/src/styles/input.css
Normal file
15
cv-project/src/styles/input.css
Normal file
|
@ -0,0 +1,15 @@
|
|||
.input {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 1.3rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.input label {
|
||||
padding: 10px 0 5px 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.input input {
|
||||
font-size: 1.3rem;
|
||||
}
|
Loading…
Reference in a new issue