rebuild portfolio: Next.js 16, React 19, Tailwind v4, homelab page, CI/CD
All checks were successful
Build and Deploy / deploy (push) Successful in 1m0s
All checks were successful
Build and Deploy / deploy (push) Successful in 1m0s
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const Footer = () => (
|
||||
<footer>
|
||||
<span class='copyright'>© 2021 Tyler Koenig</span>
|
||||
<div class='foot__links'>
|
||||
<a
|
||||
href='https://github.com/lerko96'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
title='github'
|
||||
>
|
||||
<i class='fa fa-github fa-2x' aria-hidden='true'></i>
|
||||
</a>
|
||||
<a
|
||||
href='https://www.linkedin.com/in/tyler-koenig-72607a18b/'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
title='LinkedIn'
|
||||
>
|
||||
<i class='fa fa-linkedin-square fa-2x' aria-hidden='true'></i>
|
||||
</a>
|
||||
<a
|
||||
href='mailto:tylerkng96@icloud.com'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
title='email'
|
||||
>
|
||||
<i class='fa fa-envelope-o fa-2x' aria-hidden='true'></i>
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
|
||||
export default Footer;
|
||||
38
src/components/Footer.tsx
Normal file
38
src/components/Footer.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="border-t border-[var(--color-grey-1)] py-8 mt-16">
|
||||
<div className="max-w-5xl mx-auto px-6 flex flex-col sm:flex-row items-center justify-between gap-4">
|
||||
<p className="font-mono text-xs text-[var(--color-grey-2)] tracking-widest">
|
||||
© {new Date().getFullYear()} Tyler Koenig
|
||||
</p>
|
||||
<div className="flex items-center gap-5">
|
||||
<a
|
||||
href="https://github.com/lerko96"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="GitHub"
|
||||
className="text-[var(--color-grey-2)] hover:text-[var(--color-green)] transition-colors"
|
||||
>
|
||||
<i className="fab fa-github text-lg" aria-hidden="true" />
|
||||
</a>
|
||||
<a
|
||||
href="https://www.linkedin.com/in/tyler-koenig"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="LinkedIn"
|
||||
className="text-[var(--color-grey-2)] hover:text-[var(--color-green)] transition-colors"
|
||||
>
|
||||
<i className="fab fa-linkedin text-lg" aria-hidden="true" />
|
||||
</a>
|
||||
<a
|
||||
href="mailto:tylerkoenig96@gmail.com"
|
||||
aria-label="Email"
|
||||
className="text-[var(--color-grey-2)] hover:text-[var(--color-green)] transition-colors"
|
||||
>
|
||||
<i className="fas fa-envelope text-lg" aria-hidden="true" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
64
src/components/Hero.tsx
Normal file
64
src/components/Hero.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import Image from "next/image";
|
||||
|
||||
export default function Hero() {
|
||||
return (
|
||||
<section className="flex flex-col sm:flex-row items-center sm:items-start gap-8 mb-20">
|
||||
<div className="shrink-0">
|
||||
<Image
|
||||
src="/images/headshot-tyler_koenig.png"
|
||||
alt="Tyler Koenig"
|
||||
width={120}
|
||||
height={120}
|
||||
className="rounded-full border-2 border-[var(--color-green-darker)]"
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4 text-center sm:text-left">
|
||||
<div>
|
||||
<h1 className="font-mono text-2xl font-bold text-[var(--color-text-light)] tracking-wide">
|
||||
Tyler Koenig
|
||||
</h1>
|
||||
<p className="font-mono text-sm text-[var(--color-green)] tracking-widest uppercase mt-1">
|
||||
SOC Helpdesk I by day, building beyond the title
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p className="text-[var(--color-grey-3)] text-sm leading-relaxed max-w-lg">
|
||||
I write software and run infrastructure that goes well past what my job
|
||||
title implies. Games, AI tooling, mobile apps, and a homelab running
|
||||
20+ self-hosted services on segmented VLANs. Continuously learning
|
||||
by building things that actually work.
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-5 justify-center sm:justify-start">
|
||||
<a
|
||||
href="https://github.com/lerko96"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="GitHub"
|
||||
className="text-[var(--color-grey-2)] hover:text-[var(--color-green)] transition-colors"
|
||||
>
|
||||
<i className="fab fa-github text-xl" aria-hidden="true" />
|
||||
</a>
|
||||
<a
|
||||
href="https://www.linkedin.com/in/tyler-koenig"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="LinkedIn"
|
||||
className="text-[var(--color-grey-2)] hover:text-[var(--color-green)] transition-colors"
|
||||
>
|
||||
<i className="fab fa-linkedin text-xl" aria-hidden="true" />
|
||||
</a>
|
||||
<a
|
||||
href="mailto:tylerkoenig96@gmail.com"
|
||||
aria-label="Email"
|
||||
className="text-[var(--color-grey-2)] hover:text-[var(--color-green)] transition-colors"
|
||||
>
|
||||
<i className="fas fa-envelope text-xl" aria-hidden="true" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const Nav = () => (
|
||||
<header>
|
||||
<nav>
|
||||
<div id='logo'>
|
||||
<a href='index.html'>tk</a>
|
||||
</div>
|
||||
<div id='nav__list'>
|
||||
<ul>
|
||||
{/* <li id='nav__contact'>
|
||||
<a href='#contact' target='_self'>
|
||||
CONTACT
|
||||
</a>
|
||||
</li> */}
|
||||
<li>
|
||||
<a href='#profile' target='_self'>
|
||||
PROFILE
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='#projects' target='_self'>
|
||||
PROJECTS
|
||||
</a>
|
||||
</li>
|
||||
{/* <li>
|
||||
<button onClick={() => setDarkMode(!darkMode)}>
|
||||
Toggle Dark Mode
|
||||
</button>
|
||||
</li> */}
|
||||
{/* <li>
|
||||
<a href='#skills' target='_self'>
|
||||
SKILLS
|
||||
</a>
|
||||
</li> */}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
|
||||
export default Nav;
|
||||
51
src/components/Nav.tsx
Normal file
51
src/components/Nav.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
|
||||
const links = [
|
||||
{ href: "/", label: "Home" },
|
||||
{ href: "/homelab/", label: "Homelab" },
|
||||
{ href: "/archive/", label: "Archive" },
|
||||
];
|
||||
|
||||
export default function Nav() {
|
||||
const pathname = usePathname();
|
||||
return (
|
||||
<header className="sticky top-0 z-50 bg-[var(--color-bg-deep)] border-b border-[var(--color-grey-1)]">
|
||||
<nav className="max-w-5xl mx-auto px-6 h-14 flex items-center justify-between">
|
||||
<Link
|
||||
href="/"
|
||||
className="font-mono text-xl font-bold text-[var(--color-green)] tracking-widest hover:opacity-80 transition-opacity"
|
||||
>
|
||||
tk
|
||||
</Link>
|
||||
|
||||
<div className="flex items-center gap-6">
|
||||
<ul className="flex gap-6">
|
||||
{links.map(({ href, label }) => {
|
||||
const active = pathname === href || pathname === href.replace(/\/$/, "");
|
||||
return (
|
||||
<li key={href}>
|
||||
<Link
|
||||
href={href}
|
||||
aria-current={active ? "page" : undefined}
|
||||
className={`text-xs font-mono tracking-widest uppercase transition-colors ${
|
||||
active
|
||||
? "text-[var(--color-green)]"
|
||||
: "text-[var(--color-grey-3)] hover:text-[var(--color-grey-4)]"
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import headshot from '../images/headshot-tyler_koenig.png';
|
||||
|
||||
// function Greet() {
|
||||
// return <p>Hello TK</p>
|
||||
// }
|
||||
|
||||
const Profile = () => (
|
||||
<section id='profile'>
|
||||
<article class='profile__card'>
|
||||
<div class='card__img'>
|
||||
<img id='headshot' src={headshot} alt='tyler' />
|
||||
</div>
|
||||
<div class='card__bio'>
|
||||
<div class='bio__name'>
|
||||
<a href='index.html'>TYLER KOENIG</a>
|
||||
</div>
|
||||
<div class='bio__desc'>
|
||||
<p>SOFTWARE DEVELOPER</p>
|
||||
</div>
|
||||
<div class='bio__contacts' id='contact'>
|
||||
<a
|
||||
href='https://www.linkedin.com/in/tyler-koenig-72607a18b/'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
title='LinkedIn'
|
||||
>
|
||||
<i
|
||||
class='fa fa-linkedin-square fa-2x'
|
||||
aria-hidden='true'
|
||||
></i>
|
||||
</a>
|
||||
<a
|
||||
href='https://github.com/lerko96'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
title='github'
|
||||
>
|
||||
<i class='fa fa-github fa-2x' aria-hidden='true'></i>
|
||||
</a>
|
||||
<a
|
||||
href='mailto:tylerkng96@icloud.com'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
title='email'
|
||||
>
|
||||
<i
|
||||
class='fa fa-envelope-o fa-2x'
|
||||
aria-hidden='true'
|
||||
></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<article class='profile__about'>
|
||||
<h2>about</h2>
|
||||
<p>
|
||||
Full-Stack Java Developer, with a focus on Front-End
|
||||
Development. I graduated with an Associate of Arts from Lorain
|
||||
County Community College in Spring of 2018. I began building
|
||||
HTML, CSS and JavaScript projects by the Summer of 2020 from
|
||||
courses provided on Udemy. I received my Certificate in Software
|
||||
Development from We Can Code IT in Fall of 2021. Thanks to the
|
||||
courses I've taken, I have developed strong skills needed for
|
||||
working in remote team environments, and ones that utilize Scrum
|
||||
and Agile practices. My passion comes from seeing ideas be
|
||||
brought to life. Let's get to work.
|
||||
</p>
|
||||
</article>
|
||||
<article class='profile__skills' id='skills'>
|
||||
<h2>skills</h2>
|
||||
<ul>
|
||||
<li>Java</li>
|
||||
<li>Spring</li>
|
||||
<li>MVC</li>
|
||||
<li>JavaScript</li>
|
||||
<li>JSON</li>
|
||||
<li>Restful APIs</li>
|
||||
<li>Test Driven Development</li>
|
||||
<li>Relational Databases</li>
|
||||
<li>Git</li>
|
||||
<li>Agile/ Scrum</li>
|
||||
<li>HTML</li>
|
||||
<li>CSS</li>
|
||||
<li>SCSS</li>
|
||||
<li>React</li>
|
||||
<li>Responsive Design</li>
|
||||
<li>Thymeleaf</li>
|
||||
{/* <li>Object Oriented Programming</li> */}
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
);
|
||||
|
||||
export default Profile;
|
||||
69
src/components/ProjectCard.tsx
Normal file
69
src/components/ProjectCard.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import type { Project } from "@/data/projects";
|
||||
|
||||
type Props = {
|
||||
project: Project;
|
||||
reversed?: boolean;
|
||||
};
|
||||
|
||||
export default function ProjectCard({ project, reversed = false }: Props) {
|
||||
return (
|
||||
<article className={`group flex flex-col ${reversed ? "sm:flex-row-reverse" : "sm:flex-row"} gap-6 mb-16`}>
|
||||
{/* Gradient image tile */}
|
||||
<a
|
||||
href={project.githubUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="shrink-0 sm:w-56 h-36 rounded-lg overflow-hidden"
|
||||
aria-label={`View ${project.title} on GitHub`}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<div
|
||||
className={`w-full h-full bg-gradient-to-br ${project.gradient} flex items-center justify-center transition-transform duration-300 group-hover:scale-105`}
|
||||
>
|
||||
<span className="font-mono text-xs text-[var(--color-green)] opacity-60 tracking-widest">
|
||||
{project.slug}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{/* Content */}
|
||||
<div className={`flex flex-col justify-center gap-3 ${reversed ? "sm:text-right sm:items-end" : ""}`}>
|
||||
{/* Animated accent bar */}
|
||||
<div
|
||||
className={`h-0.5 w-8 bg-[var(--color-grey-1)] rounded-full transition-all duration-300 group-hover:w-16 group-hover:bg-[var(--color-green-darker)] ${reversed ? "self-end" : ""}`}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<a
|
||||
href={project.githubUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="font-mono text-base font-semibold text-[var(--color-text-light)] hover:text-[var(--color-green)] transition-colors"
|
||||
>
|
||||
{project.title}
|
||||
</a>
|
||||
{project.stats && (
|
||||
<span className="font-mono text-xs text-[var(--color-green)] ml-3 opacity-70">
|
||||
{project.stats}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-[var(--color-grey-3)] leading-relaxed max-w-md">
|
||||
{project.description}
|
||||
</p>
|
||||
|
||||
<div className={`flex flex-wrap gap-2 ${reversed ? "justify-end" : ""}`}>
|
||||
{project.tags.map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="font-mono text-xs px-2 py-0.5 border border-[var(--color-grey-1)] text-[var(--color-grey-2)] rounded"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
@@ -1,287 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import wereHooked from '../images/were-hooked.png';
|
||||
import donutClicker from '../images/donut-clicker.png';
|
||||
import mysteryEducator from '../images/mystery-educator.png';
|
||||
import trekkingSite from '../images/trek.png';
|
||||
// import reviewSite from '../images/review-site.png';
|
||||
|
||||
const Projects = () => (
|
||||
<section id='projects'>
|
||||
<h2>projects</h2>
|
||||
|
||||
<article class='project'>
|
||||
<a
|
||||
class='project__img_link'
|
||||
href='https://github.com/lerko96/were-hooked-repo'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
<img
|
||||
src={wereHooked}
|
||||
class='project__img'
|
||||
alt='were-hooked-img'
|
||||
/>
|
||||
</a>
|
||||
<div class='project__text'>
|
||||
<h3 class='project__title'>
|
||||
<a
|
||||
href='https://github.com/lerko96/were-hooked-repo'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
We're Hooked
|
||||
</a>
|
||||
</h3>
|
||||
<div class='project__subtitle_small'>
|
||||
<time datetime='2021-08-20 12:00:00'>
|
||||
<i class='fa fa-calendar mr-2'></i>Fri, August 20th 2021
|
||||
</time>
|
||||
</div>
|
||||
<div class='project__bar'></div>
|
||||
<div class='project__info'>
|
||||
<p>
|
||||
Designed, built and tested an MVC application that
|
||||
allows users to discover fishing locations in Ohio, as
|
||||
well as teach beginners how to get started fishing and
|
||||
the current regulations that are needed to follow. This
|
||||
project was built between a team of five in a completely
|
||||
remote environment with the help of Github, Zoom and
|
||||
Slack.
|
||||
</p>
|
||||
</div>
|
||||
<ul class='project__tagbox'>
|
||||
<li class='tag__item'>Java</li>
|
||||
<li class='tag__item'>Spring</li>
|
||||
<li class='tag__item'>JavaScript</li>
|
||||
<li class='tag__item'>Restful API</li>
|
||||
<li class='tag__item'>Thymeleaf</li>
|
||||
<li class='tag__item'>HTML</li>
|
||||
<li class='tag__item'>CSS</li>
|
||||
<li class='tag__item'>Responsive Design</li>
|
||||
{/* <li class='tag__item'>TDD</li> */}
|
||||
{/* <li class='tag__item'>VS Code</li> */}
|
||||
<li class='tag__item'>Git</li>
|
||||
<li class='tag__item'>Agile</li>
|
||||
<li class='tag__item'>Scrum</li>
|
||||
<li class='tag__item'>Zoom</li>
|
||||
<li class='tag__item'>Slack</li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
<article class='project'>
|
||||
<a
|
||||
class='project__img_link'
|
||||
href='https://github.com/lerko96/mystery-educator'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
<img class='project__img' src={mysteryEducator} alt='' />
|
||||
</a>
|
||||
<div class='project__text'>
|
||||
<h3 class='project__title'>
|
||||
<a
|
||||
href='https://github.com/lerko96/mystery-educator'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
Mystery Educator
|
||||
</a>
|
||||
</h3>
|
||||
<div class='project__subtitle_small'>
|
||||
<time datetime='2021-07-23 12:00:00'>
|
||||
<i class='fas fa-calendar-alt mr-2'></i>Fri, July 23rd
|
||||
2021
|
||||
</time>
|
||||
</div>
|
||||
<div class='project__bar'></div>
|
||||
<div class='project__info'>
|
||||
<p>
|
||||
Designed, built and tested a single page application
|
||||
that renders unique data from the MET Museum and NASA
|
||||
APIs each time you visit. We also built a local backend
|
||||
database to store historical information. This project
|
||||
was built between a team of four in a completely remote
|
||||
environemnt with the help of Github, Zoom, and Slack.
|
||||
</p>
|
||||
</div>
|
||||
<ul class='project__tagbox'>
|
||||
<li class='tag__item'>JavaScript</li>
|
||||
|
||||
<li class='tag__item'>Node.js</li>
|
||||
<li class='tag__item'>Spring</li>
|
||||
<li class='tag__item'>RESTful APIs</li>
|
||||
<li class='tag__item'>Java</li>
|
||||
<li class='tag__item'>HTML</li>
|
||||
<li class='tag__item'>CSS</li>
|
||||
<li class='tag__item'>Responsive Design</li>
|
||||
{/* <li class='tag__item'>TDD</li> */}
|
||||
{/* <li class='tag__item'>VS Code</li> */}
|
||||
<li class='tag__item'>Git</li>
|
||||
<li class='tag__item'>Agile</li>
|
||||
<li class='tag__item'>Scrum</li>
|
||||
<li class='tag__item'>Zoom</li>
|
||||
<li class='tag__item'>Slack</li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
<article class='project'>
|
||||
<a
|
||||
class='project__img_link'
|
||||
href='https://github.com/lerko96/donut-clicker-lerko96'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
<img
|
||||
class='project__img'
|
||||
src={donutClicker}
|
||||
alt='donut-clicker-img'
|
||||
/>
|
||||
</a>
|
||||
<div class='project__text'>
|
||||
<h3 class='project__title'>
|
||||
<a
|
||||
href='https://github.com/lerko96/donut-clicker-lerko96'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
Donut Clicker
|
||||
</a>
|
||||
</h3>
|
||||
<div class='project__subtitle_small'>
|
||||
<time datetime='2021-07-09 12:00:00'>
|
||||
<i class='fas fa-calendar-alt mr-2'></i>Fri, July 9th
|
||||
2021
|
||||
</time>
|
||||
</div>
|
||||
<div class='project__bar'></div>
|
||||
<div class='project__info'>
|
||||
<p>
|
||||
Designed, built and tested a single page application
|
||||
that lets users make virtual donuts via clicking. Once
|
||||
enough donuts are made you have the ability to purchase
|
||||
upgrades such as auto-clickers and clicking-multipliers.
|
||||
</p>
|
||||
</div>
|
||||
<ul class='project__tagbox'>
|
||||
<li class='tag__item'>JavaScript</li>
|
||||
<li class='tag__item'>Node.js</li>
|
||||
<li class='tag__item'>HTML</li>
|
||||
<li class='tag__item'>CSS</li>
|
||||
<li class='tag__item'>Responsive Design</li>
|
||||
<li class='tag__item'>TDD</li>
|
||||
{/* <li class='tag__item'>VS Code</li> */}
|
||||
<li class='tag__item'>Git</li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
<article class='project'>
|
||||
<a
|
||||
class='project__img_link'
|
||||
href='https://github.com/lerko96/trek'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
<img
|
||||
class='project__img'
|
||||
src={trekkingSite}
|
||||
alt='trekking-img'
|
||||
/>
|
||||
</a>
|
||||
<div class='project__text'>
|
||||
<h3 class='project__title'>
|
||||
<a
|
||||
href='https://github.com/lerko96/trek'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
Trekking Site
|
||||
</a>
|
||||
</h3>
|
||||
<div class='project__subtitle_small'>
|
||||
<time datetime='2021-06-18 12:00:00'>
|
||||
<i class='fas fa-calendar-alt mr-2'></i>Fri, June 18th
|
||||
2021
|
||||
</time>
|
||||
</div>
|
||||
<div class='project__bar'></div>
|
||||
<div class='project__info'>
|
||||
<p>
|
||||
Designed, built and tested an MVC application that lets
|
||||
users discover treks located by continent, region and
|
||||
type. This project was built between a team of four in a
|
||||
completely remote environemnt with the help of Github,
|
||||
Zoom and Slack.
|
||||
</p>
|
||||
</div>
|
||||
<ul class='project__tagbox'>
|
||||
<li class='tag__item'>Java</li>
|
||||
<li class='tag__item'>Spring</li>
|
||||
{/* <li class='tag__item'>OOP</li> */}
|
||||
<li class='tag__item'>HTML</li>
|
||||
<li class='tag__item'>CSS</li>
|
||||
<li class='tag__item'>Responsive Design</li>
|
||||
<li class='tag__item'>TDD</li>
|
||||
{/* <li class='tag__item'>IntelliJ</li> */}
|
||||
<li class='tag__item'>Git</li>
|
||||
<li class='tag__item'>Agile</li>
|
||||
<li class='tag__item'>Scrum</li>
|
||||
<li class='tag__item'>Zoom</li>
|
||||
<li class='tag__item'>Slack</li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
{/* <article class='project'>
|
||||
<a
|
||||
class='project__img_link'
|
||||
href='https://github.com/lerko96/reviews-mvc'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
<img
|
||||
class='project__img'
|
||||
src={reviewSite}
|
||||
alt='review-site-img'
|
||||
/>
|
||||
</a>
|
||||
<div class='project__text'>
|
||||
<h3 class='project__title'>
|
||||
<a
|
||||
href='https://github.com/lerko96/reviews-mvc'
|
||||
rel='noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
Movie Reviews
|
||||
</a>
|
||||
</h3>
|
||||
<div class='project__subtitle_small'>
|
||||
<time datetime='2021-06-04 12:00:00'>
|
||||
<i class='fas fa-calendar-alt mr-2'></i>Fri, June 4th
|
||||
2021
|
||||
</time>
|
||||
</div>
|
||||
<div class='project__bar'></div>
|
||||
<div class='project__info'>
|
||||
<p>
|
||||
Designed, built and tested a Java application for movie
|
||||
reviews.
|
||||
</p>
|
||||
</div>
|
||||
<ul class='project__tagbox'>
|
||||
<li class='tag__item'>Java</li>
|
||||
<li class='tag__item'>SpringJPA</li>
|
||||
<li class='tag__item'>OOP</li>
|
||||
<li class='tag__item'>Thymeleaf</li>
|
||||
<li class='tag__item'>HTML</li>
|
||||
<li class='tag__item'>CSS</li>
|
||||
<li class='tag__item'>Responsive Design</li>
|
||||
<li class='tag__item'>TDD</li>
|
||||
<li class='tag__item'>IntelliJ</li>
|
||||
<li class='tag__item'>Github</li>
|
||||
</ul>
|
||||
</div>
|
||||
</article> */}
|
||||
</section>
|
||||
);
|
||||
|
||||
export default Projects;
|
||||
54
src/components/Skills.tsx
Normal file
54
src/components/Skills.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
const skillGroups = [
|
||||
{
|
||||
label: "Languages",
|
||||
skills: ["JavaScript", "TypeScript", "HTML", "CSS"],
|
||||
},
|
||||
{
|
||||
label: "Frontend & Mobile",
|
||||
skills: ["React", "React Native", "Expo", "Next.js", "Three.js", "Responsive Design"],
|
||||
},
|
||||
{
|
||||
label: "Desktop & Tools",
|
||||
skills: ["Electron", "Node.js", "REST APIs", "Git", "Docker", "TDD"],
|
||||
},
|
||||
{
|
||||
label: "Infrastructure",
|
||||
skills: ["Proxmox", "pfSense", "VLANs", "WireGuard", "Linux", "Caddy"],
|
||||
},
|
||||
{
|
||||
label: "Practices",
|
||||
skills: ["Agile / Scrum", "Relational Databases", "Self-hosting"],
|
||||
},
|
||||
];
|
||||
|
||||
export default function Skills() {
|
||||
return (
|
||||
<section className="mb-20" aria-labelledby="skills-heading">
|
||||
<h2
|
||||
id="skills-heading"
|
||||
className="font-mono text-xs text-[var(--color-green)] tracking-widest uppercase mb-8"
|
||||
>
|
||||
Skills
|
||||
</h2>
|
||||
<div className="flex flex-col gap-5">
|
||||
{skillGroups.map(({ label, skills }) => (
|
||||
<div key={label} className="flex flex-col xs:flex-row gap-2 xs:items-start">
|
||||
<span className="font-mono text-xs text-[var(--color-grey-2)] w-36 shrink-0 pt-0.5">
|
||||
{label}
|
||||
</span>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{skills.map((skill) => (
|
||||
<span
|
||||
key={skill}
|
||||
className="text-xs font-mono px-3 py-1 border border-[var(--color-grey-1)] text-[var(--color-grey-3)] rounded hover:border-[var(--color-green-darker)] hover:text-[var(--color-grey-4)] transition-colors"
|
||||
>
|
||||
{skill}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
12
src/components/ThemeScript.tsx
Normal file
12
src/components/ThemeScript.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
// Server component — renders a blocking inline script that sets the dark class
|
||||
// on <html> before React hydrates, preventing flash of wrong theme.
|
||||
export default function ThemeScript() {
|
||||
const script = `
|
||||
(function() {
|
||||
var stored = localStorage.getItem('lerko96-dark-mode');
|
||||
var dark = stored === null ? true : stored === 'true';
|
||||
if (dark) document.documentElement.classList.add('dark');
|
||||
})();
|
||||
`;
|
||||
return <script dangerouslySetInnerHTML={{ __html: script }} />;
|
||||
}
|
||||
Reference in New Issue
Block a user