diff --git a/src/components/Header.tsx b/src/components/Header.tsx index e1ee757..3967fb4 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,5 +1,4 @@ import { Link } from "react-router-dom"; -import EmailLink from "./EmailLink"; import { PROFILES } from "../utils/site"; export default function Header() { @@ -18,8 +17,8 @@ export default function Header() { Projects - - Sports + + Certifications Blog - ); diff --git a/src/components/ProjectCard.tsx b/src/components/ProjectCard.tsx index 157b03c..31251f4 100644 --- a/src/components/ProjectCard.tsx +++ b/src/components/ProjectCard.tsx @@ -14,11 +14,25 @@ export default function ProjectCard({ project }: { project: Project }) {

- + {project.title}

- + diff --git a/src/data/projects.ts b/src/data/projects.ts index 86237aa..9172454 100644 --- a/src/data/projects.ts +++ b/src/data/projects.ts @@ -8,6 +8,7 @@ export type Project = { pills: string[]; /** paragraphs of prose for the detail page */ body: string[]; + isCert?: boolean; }; export const PROJECTS: Project[] = [ @@ -65,6 +66,36 @@ export const PROJECTS: Project[] = [ }, ]; +export const CERTIFICATIONS: Project[] = [ + { + slug: "foundational-csharp", + title: "Foundational C# (Microsoft)", + description: + "Foundational C# course created by Microsoft, issued by FreeCodeCamp", + link: "https://www.freecodecamp.org/certification/alexavf/foundational-c-sharp-with-microsoft", + pills: ["Software Development", "C#"], + body: [ + "A course created by Microsoft, a comprehensive intro to the core concepts and the syntax of C#.", + "Worked with creating basic, logical console applications and how to work with data and properly debug using Visual Studio.", + ], + }, + { + slug: "introduction-to-frontend-development", + title: "Intro to Frontend Development (Meta)", + description: "Intro to frontend created by Meta, issued by Coursera", + link: "https://coursera.org/share/df3426a13f7bcdaa9f82f88e77554425", + pills: ["Software Development", "JavaScript", "HTML", "CSS"], + body: [ + "A course that took me through the basics of frontend development with JS, CSS, HTML and more.", + "Currently working on the full certification from Meta, including experience with React, Git, Figma and more.", + ], + }, +]; + export function findProject(slug: string | undefined) { return PROJECTS.find((p) => p.slug === slug); } + +export function findCertification(slug: string | undefined) { + return CERTIFICATIONS.find((p) => p.slug === slug); +} diff --git a/src/pages/CertificationDetail.tsx b/src/pages/CertificationDetail.tsx new file mode 100644 index 0000000..d6abf3d --- /dev/null +++ b/src/pages/CertificationDetail.tsx @@ -0,0 +1,66 @@ +import { Link, useParams } from "react-router-dom"; +import Footer from "../components/Footer"; +import NotFound from "./NotFound"; +import { findCertification } from "../data/projects"; + +export default function CertificationDetail() { + const { slug } = useParams(); + const cert = findCertification(slug); + + if (!cert) return ; + + return ( +
+ + +
+

{cert.title}

+
+ {cert.pills.map((pill) => ( +
+ {pill} +
+ ))} +
+
+ +
+ {cert.body.map((paragraph, i) => ( +

{paragraph}

+ ))} +
+ + + +
+ +

+ + < All certifications + +

+ +
+ +
+
+ ); +} diff --git a/src/pages/Certifications.tsx b/src/pages/Certifications.tsx new file mode 100644 index 0000000..110dafb --- /dev/null +++ b/src/pages/Certifications.tsx @@ -0,0 +1,52 @@ +import { Link } from "react-router-dom"; +import ProjectCard from "../components/ProjectCard"; +import Footer from "../components/Footer"; +import { CERTIFICATIONS } from "../data/projects"; + +export default function Certifications() { + return ( +
+
+

CERTIFICATIONS

+

+ Professional Certifications +

+

+ All of my personal professional certifications for different things in + the software dev /QA testing space. +

+
+ +
+ +
+

+ ALL CERTIFICATIONS +

+
+ {CERTIFICATIONS.map((project) => ( + + ))} +
+
+ +
+ +

+ + < Back home + +

+ +
+ +
+
+ ); +} diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 7e28948..99f73d8 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -7,7 +7,7 @@ import BlogRow from "../components/BlogRow"; import GameComponent from "../components/info/GameComponent"; import MusicComponent from "../components/info/MusicComponent"; import EmailLink from "../components/EmailLink"; -import { PROJECTS } from "../data/projects"; +import { PROJECTS, CERTIFICATIONS } from "../data/projects"; import { PROFILES } from "../utils/site"; export default function Home() { @@ -84,6 +84,23 @@ export default function Home() {
+
+

+ CERTIFICATIONS +

+ +
+ {CERTIFICATIONS.map((project) => ( + + ))} +
+
+ +
+

MY ACTIVITIES diff --git a/src/routes.tsx b/src/routes.tsx index 2ae1b60..e23b567 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -5,13 +5,22 @@ import ProjectDetail from "./pages/ProjectDetail"; import Sports from "./pages/Sports"; import Pictures from "./pages/Pictures"; import NotFound from "./pages/NotFound"; -import { PROJECTS, findProject } from "./data/projects"; +import { + CERTIFICATIONS, + PROJECTS, + findProject, + findCertification, +} from "./data/projects"; import type { PageMeta } from "./utils/seo"; import { profilePageGraph, projectListGraph, projectGraph, + certificationGraph, + certificationListGraph, } from "./utils/structuredData"; +import Certifications from "./pages/Certifications"; +import CertificationDetail from "./pages/CertificationDetail"; type Params = Record; @@ -78,6 +87,35 @@ export const routes: AppRoute[] = [ }; }, }, + { + path: "/certifications", + element: , + sitemapPaths: () => ["/certifications"], + meta: () => ({ + title: "Certifications — Alex Frantz", + description: + "All of my professionally-issued certifications. From software development to software testing, I am always studying something.", + path: "/certifications", + jsonLd: certificationListGraph(PROJECTS), + }), + }, + { + path: "/certifications/:slug", + element: , + sitemapPaths: () => CERTIFICATIONS.map((p) => `/certifications/${p.slug}`), + meta: (params) => { + const certification = findCertification(params.slug); + if (!certification) return null; + + return { + title: `${certification.title} — Alex Frantz`, + description: certification.description, + path: `/certifications/${certification.slug}`, + type: "article", + jsonLd: certificationGraph(certification), + }; + }, + }, { path: "/sports", element: , @@ -85,7 +123,7 @@ export const routes: AppRoute[] = [ meta: () => ({ title: "Bills, Sabres & Yankees Scores — Alex Frantz", description: - "Live Buffalo Bills, Buffalo Sabres and New York Yankees scores, plus how my fantasy football matchup is going this week.", + "Live Buffalo Bills and Buffalo Sabres scores, plus how my fantasy football matchup is going this week.", path: "/sports", }), }, diff --git a/src/utils/structuredData.ts b/src/utils/structuredData.ts index e0773fd..dae633e 100644 --- a/src/utils/structuredData.ts +++ b/src/utils/structuredData.ts @@ -119,3 +119,52 @@ export function projectGraph(project: Project): object[] { }, ]; } + +export function certificationListGraph(certifications: Project[]): object[] { + return [ + { + "@context": "https://schema.org", + "@type": "CollectionPage", + url: absoluteUrl("/projects"), + name: "Projects", + about: { "@id": PERSON_ID }, + mainEntity: { + "@type": "ItemList", + itemListElement: certifications.map((project, index) => ({ + "@type": "ListItem", + position: index + 1, + url: absoluteUrl(`/certifications/${project.slug}`), + name: project.title, + })), + }, + }, + ]; +} + +export function certificationGraph(certificate: Project): object[] { + return [ + { + "@context": "https://schema.org", + "@type": "SoftwareSourceCode", + name: certificate.title, + description: certificate.description, + url: absoluteUrl(`/projects/${certificate.slug}`), + codeRepository: certificate.link, + programmingLanguage: certificate.pills, + author: { "@id": PERSON_ID }, + }, + { + "@context": "https://schema.org", + "@type": "BreadcrumbList", + itemListElement: [ + { + "@type": "ListItem", + position: 1, + name: "Projects", + item: absoluteUrl("/certifications"), + }, + { "@type": "ListItem", position: 2, name: certificate.title }, + ], + }, + ]; +}