changed hero styling, added animations

This commit is contained in:
2025-11-06 15:17:17 -06:00
parent 261bed6e25
commit da75479555
7 changed files with 230 additions and 150 deletions

View File

@@ -19,14 +19,24 @@ export function Footer({
<footer className="border-t border-secondary bg-bg px-4 py-10">
<div className="mx-auto flex max-w-7xl flex-col items-center justify-between gap-6 md:flex-row">
<div className="text-center md:text-left">
<div className="text-xl font-extrabold tracking-wide text-text">Jody Holt</div>
<p className="text-sm text-text/70">Passion Pioneer</p>
<div className="text-xl md:text-2xl font-extrabold font-name tracking-wide text-text">
Jody Holt
</div>
<div className="text-[11px] md:text-sm text-text/70">
Passion Pioneer
</div>
</div>
<nav className="flex items-center gap-5">
<a className="text-text hover:text-primary" href="#projects">Projects</a>
<a className="text-text hover:text-primary" href="#experience">Experience</a>
<a className="text-text hover:text-primary" href="#home">Background</a>
<a className="text-text hover:text-primary" href="#projects">
Projects
</a>
<a className="text-text hover:text-primary" href="#experience">
Experience
</a>
<a className="text-text hover:text-primary" href="#home">
Background
</a>
</nav>
<div className="flex items-center gap-4 text-text">
@@ -38,14 +48,18 @@ export function Footer({
className="inline-flex h-10 w-10 items-center justify-center rounded-lg border border-secondary hover:border-primary hover:text-primary"
title={s.label}
>
{s.icon ?? <span className="h-2.5 w-2.5 rounded-full bg-current" />}
{s.icon ?? (
<span className="h-2.5 w-2.5 rounded-full bg-current" />
)}
</a>
))}
</div>
</div>
<div className="mx-auto mt-6 flex max-w-7xl items-center justify-center gap-4">
<div className="text-center text-xs text-text/60">© {year} Jody Holt All rights reserved</div>
<div className="text-center text-xs text-text/60">
© {year} Jody Holt All rights reserved
</div>
{showBackToTop && (
<button
onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
@@ -57,4 +71,4 @@ export function Footer({
</div>
</footer>
);
}
}

View File

@@ -1,47 +1,45 @@
import React from "react";
import profileImage from "../assets/jody.png";
import jodyMobile from "../assets/Jody-mobile.png";
import { useTheme } from "../hooks/useTheme";
export function Hero() {
const { theme } = useTheme(); // "a" | "b" | "c" | "d" | "e"
return (
<section className="relative w-full bg-hero">
<section key={theme} className="relative w-full bg-hero anim-fade-in">
<div className="md:hidden flex flex-col items-center text-center gap-2 min-h-[calc(100vh-64px)] py-6">
<h1
className="font-extrabold font-title tracking-wide leading-tight text-text
text-2xl underline md:decoration-secondary decoration-primary"
text-2xl underline md:decoration-secondary decoration-primary anim-pop-in"
>
Design. Develop. Deliver.
</h1>
<p className=" font-main text-sm text-text/80">
<p className=" font-main text-sm text-text/80 anim-fade-in">
Driven by a genuine passion for creation through code.
</p>
<div className="relative h-68 w-68 rounded-full overflow-hidden mb-2">
<div className="relative h-48 w-48 rounded-full overflow-hidden mb-2 anim-pop-in float-idle">
<div className="absolute inset-0 rounded-full img-glow" />
<div className="absolute inset-0 rounded-full img-glow" />
<img
src={jodyMobile}
alt="Jody Holt"
className="relative z-[1] h-full w-full object-cover select-none pointer-events-none will-change-transform"
/>
</div>
<img
src={jodyMobile}
alt="Jody Holt"
className="relative z-[1] h-full w-full object-cover select-none pointer-events-none"
/>
</div>
<h2 className="mt- font-extrabold font-title text-text leading-tight tracking-wide text-3xl">
<h2 className="mt- font-extrabold font-title text-text leading-tight tracking-wide text-3xl anim-fade-in">
Hello, Im Jody Holt
</h2>
<p className=" font-main mt-5 text-lg text-base text-text/85">
<p className=" font-main mt-2 text-[22px] text-base text-text/85 anim-fade-in">
Turning concepts into clean, functional code.
</p>
<p className=" font-main text-2xl font-semibold text-text mt-4">Its What I Do.</p>
<p className="mt-8 text-2xl text-text font-main ">I would love to connect!</p>
<div className="mt-2 mb-4 flex items-center justify-center gap-4">
<div className="mt-5 mb-4 flex items-center justify-center gap-4">
{[
{ label: "GitHub", href: "#" },
{ label: "LinkedIn", href: "#" },
@@ -51,7 +49,10 @@ export function Hero() {
key={a.label}
href={a.href}
aria-label={a.label}
className="inline-flex h-12 w-12 items-center justify-center rounded-lg border border-secondary/70 bg-secondary/20 text-text hover:border-primary hover:text-primary transition"
className="inline-flex h-12 w-12 items-center justify-center rounded-lg
border border-secondary/70 bg-secondary/20 text-text anim-base icon-hover
hover:border-primary hover:text-primary focus:outline-none focus-visible:ring-2
focus-visible:ring-primary/60"
>
<span className="h-3 w-3 rounded-full bg-current" />
</a>
@@ -59,79 +60,58 @@ export function Hero() {
</div>
</div>
{/*DESKTOP*/}
{/*____________________________________________________________________________________________________*/}
<div
className=" md:flex md:flex-col items-center hidden md: md:mx-auto px-4 w-full sm:h-[calc(100vh-80px)]
overflow-hidden"
>
<h1
className="text-text font-extrabold tracking-wide leading-tight
text-3xl sm:text-4xl md:text-3xl lg:text-5xl xl:text-6xl
underline md:decoration-secondary decoration-primary font-title
text-center lg:pt-2 xl:pt-7 anim-pop-in "
>
Design. Develop. Deliver.
</h1>
<p
className="text-text/80 text-sm sm:text-base md:text-lg lg:text-xl xl:text-2xl
font-main text-center anim-fade-in"
>
Driven by a genuine passion for creation through code.
</p>
{/*DESKTOP*/}
{/*____________________________________________________________________________________________________*/}
<div className="hidden md:block md:mx-auto max-w-7xl px-4">
<div
className="
min-h-[calc(100vh-64px)]
md:min-h-[calc(100vh-80px)]
flex flex-col md:flex-row items-start gap-10 lg:gap-10
py-8 md:py-1
"
flex items-center justify-evenly
w-full max-h-[calc(auto-400px) lg:px-5 xl:px-20"
>
<div className="shrink-0 self-start lg:pl-20">
<img
src={profileImage}
alt="Jody Holt"
className="w-[240px] sm:h-[280px] md:h-[700px] lg:h-[780px] xl:g-[800px] h-auto object-contain select-none pointer-events-none"
/>
</div>
<div className="flex-1 self-start md:pt-10 items-center text-center">
<h1
className="text-text font-extrabold tracking-wide leading-tight
text-3xl sm:text-4xl md:text-3xl lg:text-5xl xl:text-6xl underline md:decoration-secondary decoration-primary font-title"
<div className="self-end flex flex-col items-start lg:gap-1 mb-8 lg: items-center
lg:pb-22 2xl:pb-30 ">
<h5
className="font-semi-bold text-text
text-2xl sm:text-3xl md:text-2xl lg:text-2xl xl:text-4xl
font-title text-left"
>
Design. Develop. Deliver.
</h1>
<p
className="mb-10 text-text/80
text-sm sm:text-base md:text-lg lg:text-xl xl:text-2 font-main"
>
Driven by a genuine passion for creation through code.
</p>
Hello,
</h5>
<h2
className="font-extrabold text-text leading-tight tracking-wide mb-5
text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl font-title"
className="font-extrabold text-text leading-tight tracking-wide
text-2xl sm:text-3xl md:text-3xl lg:text-5xl xl:text-8xl
font-title text-left"
>
Hello, Im Jody Holt
Im Jody Holt
</h2>
<p
className="mb-3 text-text/85 md:mt-10 md:mb-5
text-base md:text-xl lg:text-2xl xl:text-3xl font-main"
className="mb-3 text-text/85 md:mt-2
text-base md:text-xl lg:text-2xl xl:text-4xl font-main"
>
Turning concepts into clean, functional code.
</p>
<p
className="mb-30 text-text/85
text-base md:text-3xl lg:text-4xl xl:text-5xl
font-semibold font-main"
>
Its What I Do.
</p>
<p
className="mb-8 text-text
text-lg md:text-4xl lg:text-5xl font-main"
>
I would love to connect!
</p>
<div className="flex items-center justify-center gap-4 md:gap-6">
<div className="flex self-start items-center justify-start gap-4 md:gap-6 mt-5">
{[
{ label: "GitHub", href: "#" },
{ label: "LinkedIn", href: "#" },
@@ -140,9 +120,11 @@ export function Hero() {
<a
key={a.label}
href={a.href}
className="inline-flex items-center justify-center rounded-xl border border-secondary/70 bg-secondary/20 text-text transition
h-10 w-10 sm:h-12 sm:w-12 md:h-14 md:w-14 lg:h-16 lg:w-16
hover:border-primary hover:text-primary"
className="inline-flex items-center justify-center rounded-xl border
border-secondary/70 bg-secondary/20 text-text transition h-10 w-10
sm:h-12 sm:w-12 md:h-14 md:w-14 lg:h-16 lg:w-16 hover:border-primary
hover:text-primary anim-base icon-hover focus:outline-none
focus-visible:ring-2 focus-visible:ring-primary/60"
aria-label={a.label}
title={a.label}
>
@@ -151,6 +133,14 @@ export function Hero() {
))}
</div>
</div>
<div className=" justify-start ">
<img
src={profileImage}
alt="Jody Holt"
className="lg:max-h-[78vh] sm:max-h-[50vh] h-auto object-contain select-none
pointer-events-none anim-pop-in will-change-transform"
/>
</div>
</div>
</div>
</section>

View File

@@ -15,12 +15,14 @@ export function Navbar({ onNav }: { onNav: (id: string) => void }) {
};
return (
<header className="sticky top-0 z-50 border-b border-secondary bg-bg/90 backdrop-blur h-16 md:h-20 font-main">
<div className="mx-auto flex h-full max-w-7xl items-center justify-between px-4">
<div className="flex items-center gap-3">
<header className="sticky top-0 z-50 border-b border-secondary bg-bg/90
backdrop-blur h-16 md:h-20 font-main w-full anim-fade-in">
<div className="flex h-full w-full items-center justify-between px-4 sm:px-6
md:px-10 lg:px-16">
<div className="flex items-center gap-3 hover-pop anim-base select-none">
<div className="leading-tight">
<div className="text-xl md:text-2xl font-extrabold font-name tracking-wide text-text">
<div className="text-xl md:text-2xl font-extrabold font-name tracking-wide
text-text">
Jody Holt
</div>
<div className="text-[11px] md:text-sm text-text/70">
@@ -29,12 +31,11 @@ export function Navbar({ onNav }: { onNav: (id: string) => void }) {
</div>
</div>
<nav className="hidden items-center gap-6 md:flex">
{links.map((l) => (
<button
key={l.id}
className="text-text hover:text-primary"
className="text-text/90 hover:text-primary anim-base hover:-translate-y-[1px] focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 rounded"
onClick={() => handleNav(l.id)}
>
{l.label}
@@ -43,7 +44,6 @@ export function Navbar({ onNav }: { onNav: (id: string) => void }) {
<ThemeToggle />
</nav>
<div className="md:hidden">
<button
aria-expanded={open}
@@ -63,7 +63,6 @@ export function Navbar({ onNav }: { onNav: (id: string) => void }) {
</div>
</div>
<div
className={`md:hidden transition-[max-height] duration-300 ${
open ? "max-h-96 overflow-visible" : "max-h-0 overflow-hidden"
@@ -80,7 +79,6 @@ export function Navbar({ onNav }: { onNav: (id: string) => void }) {
</button>
))}
<div className="pt-2">
<ThemeToggle compact />
</div>
</div>
</div>

View File

@@ -1,3 +1,4 @@
// ThemeToggle.tsx
import React from "react";
import { useTheme } from "../hooks/useTheme";
@@ -5,35 +6,56 @@ export function ThemeToggle({ compact = false }: { compact?: boolean }) {
const { theme, setTheme } = useTheme();
const themes = ["a", "b", "c", "d", "e"] as const;
const crossfadeTo = (next: typeof themes[number]) => {
// 1) capture current hero computed background (all layers resolved)
const hero = document.querySelector<HTMLElement>(".bg-hero");
const prevBg = hero ? getComputedStyle(hero).backgroundImage : "";
// 2) stash it in a CSS var & flag crossfade
const root = document.documentElement;
root.style.setProperty("--hero-bg-prev", prevBg);
root.classList.add("hero-xfade");
// 3) switch theme (your existing logic)
setTheme(next as any);
// 4) remove crossfade flag after the animation
window.setTimeout(() => {
root.classList.remove("hero-xfade");
root.style.removeProperty("--hero-bg-prev");
}, 600); // a bit > .55s animation
};
return (
<div className="relative inline-block text-text">
<details className="group">
<summary className="cursor-pointer select-none list-none inline-flex items-center gap-2 rounded px-3 py-1.5 bg-secondary/70 hover:bg-secondary focus:outline-none">
<span className="font-medium">
{compact ? "Theme" : "Toggle Theme"}
</span>
<summary className="cursor-pointer select-none list-none inline-flex items-center gap-2 rounded px-3 py-1.5 bg-secondary/70 hover:bg-secondary focus:outline-none anim-base hover-pop">
<span className="font-medium">{compact ? "Theme" : "Toggle Theme"}</span>
<span aria-hidden></span>
</summary>
<div
className="
absolute top-full mt-2
left-0 right-0 w-[calc(100vw-10rem)]
md:left-auto md:right- md:mx-0 md:w-44
rounded-lg border border-secondary bg-bg/95 p-2 shadow-xl backdrop-blur z-[70]
"
absolute top-full mt-2 z-[70] rounded-lg border border-secondary bg-bg/95 p-2 shadow-xl backdrop-blur
left-4 right-4 mx-auto w-[calc(100vw-2rem)] max-w-[18rem]
md:left-auto md:right-0 md:mx-0 md:w-44 md:max-w-none
origin-top scale-y-95 opacity-0 translate-y-[-4px]
pointer-events-none transition-all duration-300 ease-out
group-open:opacity-100 group-open:scale-y-100 group-open:translate-y-0 group-open:pointer-events-auto
"
>
<ul className="space-y-1">
{themes.map((t) => (
<li key={t}>
<button
onClick={() => setTheme(t as any)}
className={`w-full rounded px-3 py-2 text-left hover:bg-secondary/60 ${
onClick={() => crossfadeTo(t)}
className={`w-full rounded px-3 py-2 text-left hover:bg-secondary/60 anim-base ${
theme === t ? "outline outline-1 outline-primary" : ""
}`}
>
<span
className="mr-2 inline-block h-3 w-3 rounded-full align-middle"
style={{ background: `var(--color-accent-${t})` }}
style={{ background: `var(--color-accent-${t}, var(--color-primary))` }}
/>
Theme {t.toUpperCase()}
</button>