Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2a2e9005fd |
22 changed files with 177 additions and 413 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -23,7 +23,6 @@
|
||||||
"Sitecore",
|
"Sitecore",
|
||||||
"sportank",
|
"sportank",
|
||||||
"Umbraco",
|
"Umbraco",
|
||||||
"Yarborough",
|
|
||||||
"Yarbz"
|
"Yarbz"
|
||||||
],
|
],
|
||||||
"files.autoSave": "off",
|
"files.autoSave": "off",
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const fm = require("front-matter");
|
const fm = require("front-matter");
|
||||||
|
|
||||||
const siteUrl = process.env.SITE_URL || "https://www.aaronjy.me";
|
|
||||||
/** @type {import('next-sitemap').IConfig} */
|
/** @type {import('next-sitemap').IConfig} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
siteUrl,
|
siteUrl: process.env.SITE_URL || "https://www.aaronjy.me",
|
||||||
changefreq: "weekly",
|
changefreq: "weekly",
|
||||||
generateRobotsTxt: true,
|
generateRobotsTxt: true,
|
||||||
autoLastmod: false,
|
autoLastmod: false,
|
||||||
generateIndexSitemap: false,
|
generateIndexSitemap: false,
|
||||||
exclude: ["/server-sitemap-index.xml"], // <= exclude here
|
|
||||||
robotsTxtOptions: {
|
robotsTxtOptions: {
|
||||||
policies: [
|
policies: [
|
||||||
{
|
{
|
||||||
|
@ -17,25 +15,30 @@ module.exports = {
|
||||||
allow: "/",
|
allow: "/",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
additionalSitemaps: [
|
|
||||||
`${siteUrl}/server-sitemap-index.xml`, // <==== Add here
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
transform: async (config, path) => {
|
// transform: async (config, path) => {
|
||||||
const metadata = {
|
// const metadata = {
|
||||||
loc: path,
|
// loc: path
|
||||||
};
|
// }
|
||||||
|
|
||||||
if (isHomepage(path)) {
|
// if (isHomepage(path)) {
|
||||||
metadata.priority = 1;
|
// metadata.priority = 1
|
||||||
} else if (isBasePage(path)) {
|
// } else if (isBasePage(path)) {
|
||||||
metadata.priority = 0.8;
|
// metadata.priority = 0.8
|
||||||
} else if (isArticle(path)) {
|
// } else {
|
||||||
metadata.priority = 0.6;
|
// if (isArticle(path)) {
|
||||||
}
|
// metadata.priority = 0.6
|
||||||
|
// const attributes = getArticleAttibutes(`content${path}.md`)
|
||||||
|
// if (!attributes) { return null }
|
||||||
|
|
||||||
return metadata;
|
// metadata.lastmod = attributes.moddate ?? attributes.pubdate ?? null
|
||||||
},
|
|
||||||
|
// console.log('Calculated sitemap dates for article', path)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return metadata
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
function isHomepage(path) {
|
function isHomepage(path) {
|
||||||
|
@ -47,5 +50,20 @@ function isBasePage(path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isArticle(path) {
|
function isArticle(path) {
|
||||||
return path.startsWith("/writing/") || path.startsWith("/library/");
|
return path.startsWith("/writing/");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArticleAttibutes(path) {
|
||||||
|
const fileContents = fs.readFileSync(path, {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const { attributes } = fm(fileContents);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...attributes,
|
||||||
|
pubdate: attributes.pubdate?.toUTCString() ?? null,
|
||||||
|
moddate: attributes.moddate?.toUTCString() ?? null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "www-aaronjy-me",
|
"name": "www-aaronjy-me",
|
||||||
"version": "2.1.1",
|
"version": "2.1.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "www-aaronjy-me",
|
"name": "www-aaronjy-me",
|
||||||
"version": "2.1.1",
|
"version": "2.1.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@highlightjs/cdn-assets": "^11.11.1",
|
"@highlightjs/cdn-assets": "^11.11.1",
|
||||||
"@mdx-js/mdx": "^3.1.0",
|
"@mdx-js/mdx": "^3.1.0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "www-aaronjy-me",
|
"name": "www-aaronjy-me",
|
||||||
"version": "2.4.1",
|
"version": "2.1.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
|
|
@ -7,4 +7,3 @@ Host: https://www.aaronjy.me
|
||||||
|
|
||||||
# Sitemaps
|
# Sitemaps
|
||||||
Sitemap: https://www.aaronjy.me/sitemap.xml
|
Sitemap: https://www.aaronjy.me/sitemap.xml
|
||||||
Sitemap: https://www.aaronjy.me/server-sitemap-index.xml
|
|
||||||
|
|
14
public/sitemap-0.xml
Normal file
14
public/sitemap-0.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
|
||||||
|
<url><loc>https://www.aaronjy.me/</loc><priority>1</priority></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/about/</loc><priority>0.8</priority></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/cv/</loc><priority>0.8</priority></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/tags/</loc><priority>0.8</priority></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/writing/</loc><priority>0.8</priority></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/writing/attitudes-to-reading/</loc><priority>0.6</priority><pubdate>Tue, 18 Mar 2025 00:00:00 GMT</pubdate></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/writing/moving-from-github-to-forgejo/</loc><priority>0.6</priority><pubdate>Sun, 16 Mar 2025 00:00:00 GMT</pubdate></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/writing/performance-considerations-tcp-game-server/</loc><priority>0.6</priority><pubdate>Sun, 23 Feb 2025 21:12:37 GMT</pubdate></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/writing/quick-reflection-katherine-may/</loc><priority>0.6</priority><pubdate>Sun, 09 Mar 2025 00:00:00 GMT</pubdate></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/writing/static-site-on-google-cloud/</loc><priority>0.6</priority><pubdate>Wed, 01 May 2024 00:00:00 GMT</pubdate></url>
|
||||||
|
<url><loc>https://www.aaronjy.me/writing/support-content-filte-structure-changes-on-a-static-site/</loc><priority>0.6</priority><pubdate>Mon, 18 Mar 2024 16:47:32 GMT</pubdate></url>
|
||||||
|
</urlset>
|
|
@ -1,44 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
|
||||||
<url><loc>https://www.aaronjy.me/cv</loc><priority>0.8</priority></url>
|
<url><loc>https://www.aaronjy.me/cv</loc><changefreq>weekly</changefreq><priority>0.7</priority></url>
|
||||||
<url><loc>https://www.aaronjy.me/library</loc><priority>0.8</priority></url>
|
<url><loc>https://www.aaronjy.me/library</loc><changefreq>weekly</changefreq><priority>0.7</priority></url>
|
||||||
<url><loc>https://www.aaronjy.me/tags</loc><priority>0.8</priority></url>
|
<url><loc>https://www.aaronjy.me/tags</loc><changefreq>weekly</changefreq><priority>0.7</priority></url>
|
||||||
<url><loc>https://www.aaronjy.me/writing</loc><priority>0.8</priority></url>
|
<url><loc>https://www.aaronjy.me/writing</loc><changefreq>weekly</changefreq><priority>0.7</priority></url>
|
||||||
<url><loc>https://www.aaronjy.me/library/the-alchemist</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/the-invisible-man</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/wintering-the-power-of-rest-and-retreat-in-difficult-times</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/the-time-machine</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/when-the-moon-hits-your-eye</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/the-song-of-achilles</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/to-be-taught-if-fortunate</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/on-tyranny</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/the-dangers-of-smoking-in-bed</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/the-midnight-library</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/a-night-to-remember</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/sex-punishment</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/a-monster-calls</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/diary-of-an-oxygen-thief</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/1984</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/alices-adventures-in-wonderland</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/the-nature-of-alexander</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/eleven-kinds-of-loneliness</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/star-maker</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/stray-reflections</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/stasiland-stories-from-behind-the-berlin-wall</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/cities-that-shaped-the-ancient-world</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/animal-farm</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/a-wizard-of-earthsea</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/one-thousand-and-one-nights-a-retelling</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/the-tombs-of-atuan</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/childhoods-end</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/library/the-farthest-shore</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/about</loc><priority>0.8</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me</loc><priority>1</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/writing/migrating-from-github-to-forgejo</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/writing/performance-considerations-when-writing-a-tcp-game-server-in-dotnet</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/writing/deploying-aaronjy-me-on-a-google-storage-bucket</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/writing/supporting-content-file-structure-changes-on-a-static-site</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/writing/attitudes-to-reading-and-how-mine-have-changed</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/writing/a-reflection-on-wintering-by-katherine-may</loc><priority>0.6</priority></url>
|
|
||||||
<url><loc>https://www.aaronjy.me/writing/how-my-adhd-makes-handling-relationships-difficult</loc><priority>0.6</priority></url>
|
|
||||||
</urlset>
|
</urlset>
|
|
@ -7,7 +7,7 @@ import pck from "../../../package.json";
|
||||||
|
|
||||||
function Footer() {
|
function Footer() {
|
||||||
return (
|
return (
|
||||||
<footer className={`${style.footer} hide-print`} data-testid="footer">
|
<footer className={style.footer} data-testid="footer">
|
||||||
<hr />
|
<hr />
|
||||||
<nav>
|
<nav>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import styles from "./Header.module.css";
|
||||||
|
|
||||||
function Header() {
|
function Header() {
|
||||||
return (
|
return (
|
||||||
<header className={`${styles.header} hide-print`} data-testid="header">
|
<header className={styles.header} data-testid="header">
|
||||||
<nav>
|
<nav>
|
||||||
<Link href="/">Home</Link>
|
<Link href="/">Home</Link>
|
||||||
{", "}
|
{", "}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export default function Loading() {
|
|
||||||
return <p>Loading...</p>;
|
|
||||||
}
|
|
|
@ -2,11 +2,8 @@ import React from "react";
|
||||||
|
|
||||||
import style from "./Resume.module.css";
|
import style from "./Resume.module.css";
|
||||||
import { markdownToHtml } from "@/services/content-service";
|
import { markdownToHtml } from "@/services/content-service";
|
||||||
import { MDXClient } from "next-mdx-remote-client/csr";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
function Resume({
|
function Resume({
|
||||||
introMdxSource,
|
|
||||||
competencies,
|
competencies,
|
||||||
education,
|
education,
|
||||||
certifications,
|
certifications,
|
||||||
|
@ -15,7 +12,7 @@ function Resume({
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className={style.cv}>
|
<div className={style.cv}>
|
||||||
<ol className="hide-print">
|
<ol>
|
||||||
<li>
|
<li>
|
||||||
<a href="#experience">Professional experience</a>
|
<a href="#experience">Professional experience</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -33,68 +30,57 @@ function Resume({
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
<div>
|
<div>
|
||||||
<div className={style.about}>
|
<h2 id="experience">Professional experience</h2>
|
||||||
<MDXClient {...introMdxSource} />
|
|
||||||
<span className="print-only">
|
{experience?.map((exp, i) => (
|
||||||
See more at <a href="https://aaronjy.me/cv">aaronjy.me/cv</a>
|
<div key={i}>
|
||||||
</span>
|
<WorkExperience
|
||||||
</div>
|
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>
|
</div>
|
||||||
<div className={style.cvContent}>
|
<div className="sidebar">
|
||||||
<div className={style.experience}>
|
<h2 id="competencies">Competencies</h2>
|
||||||
<h2 id="experience">Professional experience</h2>
|
<ul>
|
||||||
|
{competencies
|
||||||
{experience?.map((exp, i) => (
|
?.sort((a, b) => a.name > b.name)
|
||||||
<div key={i}>
|
.map((c, i) => (
|
||||||
<WorkExperience
|
<li key={i}>{c.name}</li>
|
||||||
employer={exp.employer}
|
|
||||||
position={exp.position}
|
|
||||||
start={exp.start}
|
|
||||||
end={exp.end}
|
|
||||||
skills={exp.skills}
|
|
||||||
>
|
|
||||||
{markdownToHtml(exp.description)}
|
|
||||||
</WorkExperience>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</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 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>
|
</ul>
|
||||||
|
|
||||||
<h2 className="education">Education</h2>
|
<h2 id="certifications">Certifications</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{education
|
{certifications
|
||||||
?.sort((a, b) => a.name - b.name)
|
?.sort((a, b) => a.name > b.name)
|
||||||
.map((c, i) => (
|
.map((c, i) => (
|
||||||
<li key={i}>{c.name}</li>
|
<li key={i}>{c.name}</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
|
<h2 className="languages">Languages</h2>
|
||||||
|
<ul>
|
||||||
|
{languages?.sort().map((c, i) => (
|
||||||
|
<li key={i}>
|
||||||
|
{c.name} - {c.proficiency}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2 className="education">Education</h2>
|
||||||
|
<p>{education.name}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -102,43 +88,23 @@ function Resume({
|
||||||
|
|
||||||
export default Resume;
|
export default Resume;
|
||||||
|
|
||||||
function WorkExperience({ position, employer, start, end, skills, children }) {
|
function WorkExperience({ position, employer, start, end, children }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<div className={style["work-experience"]}>
|
||||||
<table className={style.experienceTable}>
|
<div>
|
||||||
<tbody>
|
<h3 id={position}>
|
||||||
<tr>
|
{position}
|
||||||
<td>
|
<br />
|
||||||
<span id={position} className={style.position}>
|
<small>{employer}</small>
|
||||||
{position}
|
</h3>
|
||||||
</span>
|
<small>
|
||||||
<br />
|
<time>{start}</time> - <time>{end}</time>
|
||||||
<span className={style.employer}>{employer}</span>
|
</small>
|
||||||
</td>
|
</div>
|
||||||
<td className="text-right">
|
<div
|
||||||
<time>{start}</time> - <time>{end}</time>
|
data-test="children"
|
||||||
</td>
|
dangerouslySetInnerHTML={{ __html: children }}
|
||||||
</tr>
|
/>
|
||||||
<tr>
|
</div>
|
||||||
<td colSpan={2}>
|
|
||||||
<div
|
|
||||||
data-test="children"
|
|
||||||
dangerouslySetInnerHTML={{ __html: children }}
|
|
||||||
className={style.experienceContent}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{!!skills?.length && (
|
|
||||||
<div className={style.skillList}>
|
|
||||||
{skills.sort().map((skill) => (
|
|
||||||
<span key={skill}>{skill}</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<hr />
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
.experienceTable {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.position {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cvContent {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
gap: 0.5em;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cvContent ol,
|
|
||||||
.cvContent ul {
|
|
||||||
padding: 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skillList {
|
|
||||||
font-size: 0.8em;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skillList span {
|
|
||||||
background-color: var(--dark);
|
|
||||||
color: var(--light);
|
|
||||||
padding: 0 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.experienceContent > p {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.cvContent {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cvContent .sidebar {
|
|
||||||
height: auto;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
.cvContent .experience {
|
|
||||||
flex-basis: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cvContent .sidebar {
|
|
||||||
flex-basis: 20%;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +1,34 @@
|
||||||
import Loading from "@/components/Loading/Loading";
|
import {
|
||||||
import { FailedFetchBasicPagesError } from "@/errors";
|
FailedFetchBasicPageError,
|
||||||
|
FailedFetchBasicPagesError,
|
||||||
|
} from "@/errors";
|
||||||
import DefaultLayout from "@/layouts/DefaultLayout/DefaultLayout";
|
import DefaultLayout from "@/layouts/DefaultLayout/DefaultLayout";
|
||||||
import { mdxComponents } from "@/lib/mdx-components";
|
import { mdxComponents } from "@/lib/mdx-components";
|
||||||
import { fetchBasicPages } from "@/services/content-service";
|
import { fetchBasicPages } from "@/services/content-service";
|
||||||
import { MDXClient } from "next-mdx-remote-client";
|
import { MDXClient } from "next-mdx-remote-client";
|
||||||
import { serialize } from "next-mdx-remote-client/serialize";
|
import { serialize } from "next-mdx-remote-client/serialize";
|
||||||
import { NextSeo } from "next-seo";
|
import { NextSeo } from "next-seo";
|
||||||
import { useRouter } from "next/router";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const res = await fetchBasicPages(["path"]);
|
const res = await fetchBasicPages();
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new FailedFetchBasicPagesError(await res.text());
|
throw new FailedFetchBasicPagesError();
|
||||||
}
|
}
|
||||||
|
|
||||||
const pages = (await res.json()).data;
|
const pages = (await res.json()).data;
|
||||||
|
const paths = pages.map((page) => {
|
||||||
return {
|
return {
|
||||||
paths: pages.map((page) => ({
|
|
||||||
params: {
|
params: {
|
||||||
path: [page.path ?? ""],
|
path: page.path?.split("/") ?? [],
|
||||||
},
|
},
|
||||||
})),
|
};
|
||||||
fallback: true,
|
});
|
||||||
};
|
|
||||||
|
return { paths, fallback: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ params }) {
|
export async function getStaticProps({ params }) {
|
||||||
const { path } = params;
|
const { path } = params;
|
||||||
|
|
||||||
const res = await fetchBasicPages([], {
|
const res = await fetchBasicPages([], {
|
||||||
path: {
|
path: {
|
||||||
_eq: path?.join("/") ?? null,
|
_eq: path?.join("/") ?? null,
|
||||||
|
@ -45,7 +44,6 @@ export async function getStaticProps({ params }) {
|
||||||
if (!page) {
|
if (!page) {
|
||||||
return {
|
return {
|
||||||
notFound: true,
|
notFound: true,
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,16 +60,6 @@ export async function getStaticProps({ params }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BasicPage({ title, mdxSource }) {
|
export default function BasicPage({ title, mdxSource }) {
|
||||||
const { isFallback } = useRouter();
|
|
||||||
|
|
||||||
if (isFallback) {
|
|
||||||
return (
|
|
||||||
<DefaultLayout>
|
|
||||||
<Loading />
|
|
||||||
</DefaultLayout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mdxSource || "error" in mdxSource) {
|
if (!mdxSource || "error" in mdxSource) {
|
||||||
return <p>Something went wrong: {mdxSource?.error ?? "???"}</p>;
|
return <p>Something went wrong: {mdxSource?.error ?? "???"}</p>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
import Resume from "@/components/Resume/Resume";
|
|
||||||
import { FailedFetchCVError } from "@/errors";
|
|
||||||
import DefaultLayout from "@/layouts/DefaultLayout/DefaultLayout";
|
import DefaultLayout from "@/layouts/DefaultLayout/DefaultLayout";
|
||||||
import { fetchCV } from "@/services/content-service";
|
import React from "react";
|
||||||
import { NextSeo } from "next-seo";
|
import { NextSeo } from "next-seo";
|
||||||
|
import Resume from "@/components/Resume/Resume";
|
||||||
import style from "./cv.module.css";
|
import { fetchCV } from "@/services/content-service";
|
||||||
import { serialize } from "next-mdx-remote-client/serialize";
|
import { FailedFetchCVError } from "@/errors";
|
||||||
|
|
||||||
export const Title = "CV";
|
export const Title = "CV";
|
||||||
|
|
||||||
export async function getStaticProps() {
|
export async function getServerSideProps() {
|
||||||
const res = await fetchCV([]);
|
const res = await fetchCV([]);
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
@ -20,36 +18,23 @@ export async function getStaticProps() {
|
||||||
if (!cv) {
|
if (!cv) {
|
||||||
return {
|
return {
|
||||||
notFound: true,
|
notFound: true,
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { competencies, education, languages, certifications, experience } = cv;
|
||||||
intro,
|
|
||||||
competencies,
|
|
||||||
education,
|
|
||||||
languages,
|
|
||||||
certifications,
|
|
||||||
experience,
|
|
||||||
} = cv;
|
|
||||||
|
|
||||||
const introMdxSource = await serialize({ source: intro });
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
introMdxSource,
|
|
||||||
competencies,
|
competencies,
|
||||||
education,
|
education,
|
||||||
languages,
|
languages,
|
||||||
certifications,
|
certifications,
|
||||||
experience,
|
experience,
|
||||||
},
|
},
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ResumePage({
|
export default function ResumePage({
|
||||||
introMdxSource,
|
|
||||||
competencies,
|
competencies,
|
||||||
education,
|
education,
|
||||||
certifications,
|
certifications,
|
||||||
|
@ -64,11 +49,9 @@ export default function ResumePage({
|
||||||
title: Title,
|
title: Title,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<h1 className="hide-print">{Title}</h1>
|
<h1>{Title}</h1>
|
||||||
<h1 className={`${style.printHeading} print-only`}>Aaron Yarborough</h1>
|
|
||||||
<section>
|
<section>
|
||||||
<Resume
|
<Resume
|
||||||
introMdxSource={introMdxSource}
|
|
||||||
competencies={competencies}
|
competencies={competencies}
|
||||||
education={education}
|
education={education}
|
||||||
certifications={certifications}
|
certifications={certifications}
|
||||||
|
|
|
@ -6,33 +6,37 @@ import {
|
||||||
FailedFetchBookReviewError,
|
FailedFetchBookReviewError,
|
||||||
FailedFetchBookReviewsError,
|
FailedFetchBookReviewsError,
|
||||||
} from "@/errors";
|
} from "@/errors";
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import Loading from "@/components/Loading/Loading";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
// export async function getStaticPaths () {
|
||||||
const res = await fetchBookReviews(["slug"], {
|
// const res = await fetchBookReviews(['slug'], {
|
||||||
status: "published",
|
// status: 'published'
|
||||||
});
|
// })
|
||||||
|
|
||||||
if (!res.ok) {
|
// if (!res.ok) {
|
||||||
throw new FailedFetchBookReviewsError(await res.text());
|
// throw new FailedFetchBookReviewsError(await res.text())
|
||||||
}
|
// }
|
||||||
|
|
||||||
const reviews = (await res.json()).data;
|
// const reviews = (await res.json()).data
|
||||||
|
|
||||||
return {
|
// return {
|
||||||
paths: reviews.map((post) => ({
|
// paths: reviews.map(post => ({
|
||||||
params: {
|
// params: {
|
||||||
slug: post.slug,
|
// slug: post.slug
|
||||||
},
|
// }
|
||||||
})),
|
// })),
|
||||||
fallback: true,
|
// fallback: false // false or "blocking"
|
||||||
};
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const getStaticProps = async ({ params }) => {
|
export const getServerSideProps = async ({ params }) => {
|
||||||
const { slug } = params;
|
const { slug } = params;
|
||||||
|
|
||||||
|
if (!slug) {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const res = await fetchBookReviews([], {
|
const res = await fetchBookReviews([], {
|
||||||
slug,
|
slug,
|
||||||
status: "published",
|
status: "published",
|
||||||
|
@ -46,7 +50,6 @@ export const getStaticProps = async ({ params }) => {
|
||||||
if (!review) {
|
if (!review) {
|
||||||
return {
|
return {
|
||||||
notFound: true,
|
notFound: true,
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,17 +61,13 @@ export const getStaticProps = async ({ params }) => {
|
||||||
review,
|
review,
|
||||||
html,
|
html,
|
||||||
},
|
},
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function LibrarySingle({ review, html }) {
|
export default function LibrarySingle({ review, html }) {
|
||||||
const { isFallback } = useRouter();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultLayout>
|
<DefaultLayout>
|
||||||
{!isFallback && <BookReview review={review} html={html} />}
|
<BookReview review={review} html={html} />
|
||||||
{isFallback && <Loading />}
|
|
||||||
</DefaultLayout>
|
</DefaultLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { NextSeo } from "next-seo";
|
||||||
|
|
||||||
export const Title = "Library";
|
export const Title = "Library";
|
||||||
|
|
||||||
export async function getStaticProps() {
|
export async function getServerSideProps() {
|
||||||
const res = await fetchBookReviews();
|
const res = await fetchBookReviews();
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
@ -23,7 +23,6 @@ export async function getStaticProps() {
|
||||||
props: {
|
props: {
|
||||||
reviews: stringifyAndParse(reviews),
|
reviews: stringifyAndParse(reviews),
|
||||||
},
|
},
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import {
|
|
||||||
fetchBasicPages,
|
|
||||||
fetchBookReviews,
|
|
||||||
fetchPosts,
|
|
||||||
} from "@/services/content-service";
|
|
||||||
import { getServerSideSitemapIndexLegacy } from "next-sitemap";
|
|
||||||
|
|
||||||
const siteUrl = process.env.SITE_URL || "https://www.aaronjy.me";
|
|
||||||
|
|
||||||
export const getServerSideProps = async (ctx) => {
|
|
||||||
const [basicPagesResp, bookReviewsResp, postsResp] = await Promise.all([
|
|
||||||
fetchBasicPages().then((res) => res.json()),
|
|
||||||
fetchBookReviews().then((res) => res.json()),
|
|
||||||
fetchPosts().then((res) => res.json()),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const urls = [
|
|
||||||
...basicPagesResp.data.map((entry) => `${siteUrl}/${entry.path ?? ""}`),
|
|
||||||
...bookReviewsResp.data.map(
|
|
||||||
(entry) => `${siteUrl}/library/${entry.slug ?? ""}`,
|
|
||||||
),
|
|
||||||
...postsResp.data.map((entry) => `${siteUrl}/writing/${entry.slug ?? ""}`),
|
|
||||||
];
|
|
||||||
|
|
||||||
return getServerSideSitemapIndexLegacy(ctx, [...urls]);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Default export to prevent next.js errors
|
|
||||||
export default function SitemapIndex() {}
|
|
|
@ -9,7 +9,7 @@ import { NextSeo } from "next-seo";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export async function getStaticProps() {
|
export async function getServerSideProps() {
|
||||||
const res = await fetchPosts(["title", "date_published", "tags", "slug"], {
|
const res = await fetchPosts(["title", "date_published", "tags", "slug"], {
|
||||||
status: "published",
|
status: "published",
|
||||||
});
|
});
|
||||||
|
@ -26,7 +26,6 @@ export async function getStaticProps() {
|
||||||
tags,
|
tags,
|
||||||
posts,
|
posts,
|
||||||
},
|
},
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,31 +3,8 @@ import DefaultLayout from "@/layouts/DefaultLayout/DefaultLayout";
|
||||||
import Article from "@/components/Article/Article";
|
import Article from "@/components/Article/Article";
|
||||||
import { fetchPosts, markdownToHtml } from "@/services/content-service";
|
import { fetchPosts, markdownToHtml } from "@/services/content-service";
|
||||||
import { FailedFetchPostError, FailedFetchPostsError } from "@/errors";
|
import { FailedFetchPostError, FailedFetchPostsError } from "@/errors";
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import Loading from "@/components/Loading/Loading";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export const getServerSideProps = async ({ params }) => {
|
||||||
const res = await fetchPosts(["slug"], {
|
|
||||||
status: "published",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new FailedFetchPostsError(await res.text());
|
|
||||||
}
|
|
||||||
|
|
||||||
const posts = (await res.json()).data;
|
|
||||||
|
|
||||||
return {
|
|
||||||
paths: posts.map((post) => ({
|
|
||||||
params: {
|
|
||||||
slug: post.slug,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
fallback: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getStaticProps = async ({ params }) => {
|
|
||||||
const { slug } = params;
|
const { slug } = params;
|
||||||
const res = await fetchPosts([], {
|
const res = await fetchPosts([], {
|
||||||
slug,
|
slug,
|
||||||
|
@ -42,7 +19,6 @@ export const getStaticProps = async ({ params }) => {
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return {
|
return {
|
||||||
notFound: true,
|
notFound: true,
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,17 +30,13 @@ export const getStaticProps = async ({ params }) => {
|
||||||
post,
|
post,
|
||||||
html,
|
html,
|
||||||
},
|
},
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function WritingSingle({ post, html }) {
|
export default function WritingSingle({ post, html }) {
|
||||||
const { isFallback } = useRouter();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultLayout>
|
<DefaultLayout>
|
||||||
{!isFallback && <Article {...post} html={html} />}
|
<Article {...post} html={html} />
|
||||||
{isFallback && <Loading />}
|
|
||||||
</DefaultLayout>
|
</DefaultLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import StaticContentList from "@/components/StaticContentList/StaticContentList"
|
||||||
import { fetchPosts } from "@/services/content-service";
|
import { fetchPosts } from "@/services/content-service";
|
||||||
import { FailedFetchPostsError } from "@/errors";
|
import { FailedFetchPostsError } from "@/errors";
|
||||||
|
|
||||||
export const getStaticProps = async () => {
|
export const getServerSideProps = async () => {
|
||||||
const res = await fetchPosts(["title", "date_published", "slug"], {
|
const res = await fetchPosts(["title", "date_published", "slug"], {
|
||||||
status: "published",
|
status: "published",
|
||||||
});
|
});
|
||||||
|
@ -25,7 +25,6 @@ export const getStaticProps = async () => {
|
||||||
props: {
|
props: {
|
||||||
posts,
|
posts,
|
||||||
},
|
},
|
||||||
revalidate: 60,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,31 +22,3 @@ td:first-child {
|
||||||
.bold {
|
.bold {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-right {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.print-only {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
html {
|
|
||||||
padding-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-size: 11.5px;
|
|
||||||
line-height: 1.3;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hide-print {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.print-only {
|
|
||||||
display: initial;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue