feat: improve cv layout
This commit is contained in:
parent
6d6c468be7
commit
188edc999c
9 changed files with 224 additions and 73 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -23,6 +23,7 @@
|
|||
"Sitecore",
|
||||
"sportank",
|
||||
"Umbraco",
|
||||
"Yarborough",
|
||||
"Yarbz"
|
||||
],
|
||||
"files.autoSave": "off",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "www-aaronjy-me",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"lint-staged": {
|
||||
|
|
|
@ -7,7 +7,7 @@ import pck from "../../../package.json";
|
|||
|
||||
function Footer() {
|
||||
return (
|
||||
<footer className={style.footer} data-testid="footer">
|
||||
<footer className={`${style.footer} hide-print`} data-testid="footer">
|
||||
<hr />
|
||||
<nav>
|
||||
<div>
|
||||
|
|
|
@ -5,7 +5,7 @@ import styles from "./Header.module.css";
|
|||
|
||||
function Header() {
|
||||
return (
|
||||
<header className={styles.header} data-testid="header">
|
||||
<header className={`${styles.header} hide-print`} data-testid="header">
|
||||
<nav>
|
||||
<Link href="/">Home</Link>
|
||||
{", "}
|
||||
|
|
|
@ -2,8 +2,11 @@ import React from "react";
|
|||
|
||||
import style from "./Resume.module.css";
|
||||
import { markdownToHtml } from "@/services/content-service";
|
||||
import { MDXClient } from "next-mdx-remote-client/csr";
|
||||
import Link from "next/link";
|
||||
|
||||
function Resume({
|
||||
introMdxSource,
|
||||
competencies,
|
||||
education,
|
||||
certifications,
|
||||
|
@ -12,7 +15,7 @@ function Resume({
|
|||
}) {
|
||||
return (
|
||||
<div className={style.cv}>
|
||||
<ol>
|
||||
<ol className="hide-print">
|
||||
<li>
|
||||
<a href="#experience">Professional experience</a>
|
||||
</li>
|
||||
|
@ -30,57 +33,73 @@ function Resume({
|
|||
</li>
|
||||
</ol>
|
||||
<div>
|
||||
<h2 id="experience">Professional experience</h2>
|
||||
|
||||
{experience?.map((exp, i) => (
|
||||
<div key={i}>
|
||||
<WorkExperience
|
||||
employer={exp.employer}
|
||||
position={exp.position}
|
||||
start={exp.start}
|
||||
end={exp.end}
|
||||
>
|
||||
{markdownToHtml(exp.description)}
|
||||
</WorkExperience>
|
||||
{!!exp.skills?.length && (
|
||||
<details>
|
||||
<summary>Competencies</summary>
|
||||
<>{exp.skills.sort().join(", ")}</>
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className={style.about}>
|
||||
<MDXClient {...introMdxSource} />
|
||||
<span className="print-only">
|
||||
See more at <a href="https://aaronjy.me/cv">aaronjy.me/cv</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sidebar">
|
||||
<h2 id="competencies">Competencies</h2>
|
||||
<ul>
|
||||
{competencies
|
||||
?.sort((a, b) => a.name > b.name)
|
||||
.map((c, i) => (
|
||||
<li key={i}>{c.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className={style.cvContent}>
|
||||
<div className={style.experience}>
|
||||
<h2 id="experience">Professional experience</h2>
|
||||
|
||||
<h2 id="certifications">Certifications</h2>
|
||||
<ul>
|
||||
{certifications
|
||||
?.sort((a, b) => a.name > b.name)
|
||||
.map((c, i) => (
|
||||
<li key={i}>{c.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<h2 className="languages">Languages</h2>
|
||||
<ul>
|
||||
{languages?.sort().map((c, i) => (
|
||||
<li key={i}>
|
||||
{c.name} - {c.proficiency}
|
||||
</li>
|
||||
{experience?.map((exp, i) => (
|
||||
<div key={i}>
|
||||
<WorkExperience
|
||||
employer={exp.employer}
|
||||
position={exp.position}
|
||||
start={exp.start}
|
||||
end={exp.end}
|
||||
>
|
||||
{markdownToHtml(exp.description)}
|
||||
</WorkExperience>
|
||||
{!!exp.skills?.length && (
|
||||
<details className="hide-print">
|
||||
<summary>Competencies</summary>
|
||||
<>{exp.skills.sort().join(", ")}</>
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className={style.sidebar}>
|
||||
<h2 id="competencies">Competencies</h2>
|
||||
<ul>
|
||||
{competencies
|
||||
?.sort((a, b) => a.name - b.name)
|
||||
.map((c, i) => (
|
||||
<li key={i}>{c.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<h2 className="education">Education</h2>
|
||||
<p>{education.name}</p>
|
||||
<h2 id="certifications">Certifications</h2>
|
||||
<ul>
|
||||
{certifications
|
||||
?.sort((a, b) => a.name > b.name)
|
||||
.map((c, i) => (
|
||||
<li key={i}>{c.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<h2 className="languages">Languages</h2>
|
||||
<ul>
|
||||
{languages?.sort().map((c, i) => (
|
||||
<li key={i}>
|
||||
<strong>{c.name}</strong> - {c.proficiency}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<h2 className="education">Education</h2>
|
||||
<ul>
|
||||
{education
|
||||
?.sort((a, b) => a.name - b.name)
|
||||
.map((c, i) => (
|
||||
<li key={i}>{c.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -90,21 +109,48 @@ export default Resume;
|
|||
|
||||
function WorkExperience({ position, employer, start, end, children }) {
|
||||
return (
|
||||
<div className={style["work-experience"]}>
|
||||
<div>
|
||||
<h3 id={position}>
|
||||
{position}
|
||||
<br />
|
||||
<small>{employer}</small>
|
||||
</h3>
|
||||
<small>
|
||||
<time>{start}</time> - <time>{end}</time>
|
||||
</small>
|
||||
</div>
|
||||
<div
|
||||
data-test="children"
|
||||
dangerouslySetInnerHTML={{ __html: children }}
|
||||
/>
|
||||
</div>
|
||||
// <div className={style["work-experience"]}>
|
||||
// <div>
|
||||
// <h3 id={position}>
|
||||
// {position}
|
||||
// <br />
|
||||
// <small>{employer}</small>
|
||||
// </h3>
|
||||
// <small>
|
||||
// <time>{start}</time> - <time>{end}</time>
|
||||
// </small>
|
||||
// </div>
|
||||
// <div
|
||||
// data-test="children"
|
||||
// dangerouslySetInnerHTML={{ __html: children }}
|
||||
// />
|
||||
// </div>
|
||||
|
||||
<table className={style.experienceTable}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<span id={position} className={style.position}>
|
||||
{position}
|
||||
</span>
|
||||
<br />
|
||||
<span className={style.employer}>{employer}</span>
|
||||
</td>
|
||||
<td className="text-right">
|
||||
{/* <small> */}
|
||||
<time>{start}</time> - <time>{end}</time>
|
||||
{/* </small> */}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colSpan={2}>
|
||||
<div
|
||||
data-test="children"
|
||||
dangerouslySetInnerHTML={{ __html: children }}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
.experienceTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.position {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cvContent {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
gap: 3rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.cvContent .experience {
|
||||
flex-basis: 66.66%;
|
||||
}
|
||||
|
||||
.cvContent .sidebar {
|
||||
flex-basis: 33.33%;
|
||||
position: sticky;
|
||||
top: 10px;
|
||||
left: 0px;
|
||||
height: 1px;
|
||||
/* Needed to make sticky work */
|
||||
}
|
||||
|
||||
.about {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.cv ol,
|
||||
.cv ul {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.cvContent {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cvContent .sidebar {
|
||||
height: auto;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.cvContent {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.cvContent .experience {
|
||||
flex-basis: 80%;
|
||||
}
|
||||
|
||||
.cvContent .sidebar {
|
||||
flex-basis: 20%;
|
||||
}
|
||||
}
|
0
src/pages/cv/cv.module.css
Normal file
0
src/pages/cv/cv.module.css
Normal file
|
@ -1,9 +1,11 @@
|
|||
import DefaultLayout from "@/layouts/DefaultLayout/DefaultLayout";
|
||||
import React from "react";
|
||||
import { NextSeo } from "next-seo";
|
||||
import Resume from "@/components/Resume/Resume";
|
||||
import { fetchCV } from "@/services/content-service";
|
||||
import { FailedFetchCVError } from "@/errors";
|
||||
import DefaultLayout from "@/layouts/DefaultLayout/DefaultLayout";
|
||||
import { fetchCV } from "@/services/content-service";
|
||||
import { NextSeo } from "next-seo";
|
||||
|
||||
import style from "./cv.module.css";
|
||||
import { serialize } from "next-mdx-remote-client/serialize";
|
||||
|
||||
export const Title = "CV";
|
||||
|
||||
|
@ -22,10 +24,20 @@ export async function getStaticProps() {
|
|||
};
|
||||
}
|
||||
|
||||
const { competencies, education, languages, certifications, experience } = cv;
|
||||
const {
|
||||
intro,
|
||||
competencies,
|
||||
education,
|
||||
languages,
|
||||
certifications,
|
||||
experience,
|
||||
} = cv;
|
||||
|
||||
const introMdxSource = await serialize({ source: intro });
|
||||
|
||||
return {
|
||||
props: {
|
||||
introMdxSource,
|
||||
competencies,
|
||||
education,
|
||||
languages,
|
||||
|
@ -37,6 +49,7 @@ export async function getStaticProps() {
|
|||
}
|
||||
|
||||
export default function ResumePage({
|
||||
introMdxSource,
|
||||
competencies,
|
||||
education,
|
||||
certifications,
|
||||
|
@ -51,9 +64,11 @@ export default function ResumePage({
|
|||
title: Title,
|
||||
}}
|
||||
/>
|
||||
<h1>{Title}</h1>
|
||||
<h1 className="hide-print">{Title}</h1>
|
||||
<h1 className={`${style.printHeading} print-only`}>Aaron Yarborough</h1>
|
||||
<section>
|
||||
<Resume
|
||||
introMdxSource={introMdxSource}
|
||||
competencies={competencies}
|
||||
education={education}
|
||||
certifications={certifications}
|
||||
|
|
|
@ -22,3 +22,31 @@ td:first-child {
|
|||
.bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.print-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media print {
|
||||
html {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 12px;
|
||||
line-height: 1.3;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.hide-print {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.print-only {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue