diff --git a/README.md b/README.md index 1ed7362..174f677 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This site demonstrates my personality, skills, and presents the tone I provide t **STACK** -- SPA with React (functonal components, hooks) +- SPA with React (functional components, hooks) - TailwindCSS (custom tokens and theme system) - Theme Engine (5 themes with automated color adaption per user preference ) - IntersectionObserver (based scroll nav) @@ -37,7 +37,7 @@ src/ ## Theme System ### within index: -#### 5 unique themes are layed out by: +#### 5 unique themes are laid out by: - color-bg - color-primary - color-text @@ -50,7 +50,7 @@ These themes are applied via html[data-theme="x"] and are used across the site f ## DEV NOTES as of 10/29/2025 - All social links are dummy values as of now. -- Section layout is controlleted via
wrappers. +- Section layout is controlled via
wrappers. - Images are outdated and will be replaced. - UI is mobile-oriented, but device friendly. @@ -58,7 +58,7 @@ These themes are applied via html[data-theme="x"] and are used across the site f ## TODO - Add links to projects within cards -- Change out experiance tab for resume/skills +- Change out experience tab for resume/skills - Add animations - more ways to contact - Deploy site via personal service diff --git a/src/assets/Jody.png b/src/assets/Jody.png index dfe73a5..48b25f2 100644 Binary files a/src/assets/Jody.png and b/src/assets/Jody.png differ diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 4e8cb0c..5d00af7 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -19,14 +19,24 @@ export function Footer({ ); -} \ No newline at end of file +} diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx index 6510240..a652d5f 100644 --- a/src/components/Hero.tsx +++ b/src/components/Hero.tsx @@ -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 ( -
+

Design. Develop. Deliver.

-

+

Driven by a genuine passion for creation through code.

-
+
+
-
+ Jody Holt +
- - Jody Holt -
- -

+

Hello, I’m Jody Holt

-

+

Turning concepts into clean, functional code.

-

It’s What I Do.

+ + -

I would love to connect!

- -
+
{[ { 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" > @@ -59,79 +60,58 @@ export function Hero() {
+ {/*DESKTOP*/} + {/*____________________________________________________________________________________________________*/} +
+

+ Design. Develop. Deliver. +

+

+ Driven by a genuine passion for creation through code. +

- - - - - - - - - {/*DESKTOP*/} -{/*____________________________________________________________________________________________________*/} -
-
- Jody Holt -
- -
-

+

- Design. Develop. Deliver. -
- -

- Driven by a genuine passion for creation through code. -

- + Hello, +

- Hello, I’m Jody Holt + I’m Jody Holt

Turning concepts into clean, functional code.

-

- It’s What I Do. -

- -

- I would love to connect! -

- -
+ +
{[ { label: "GitHub", href: "#" }, { label: "LinkedIn", href: "#" }, @@ -140,9 +120,11 @@ export function Hero() { @@ -151,6 +133,14 @@ export function Hero() { ))}
+
+ Jody Holt +
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 4fa6f1d..0b392a7 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -15,12 +15,14 @@ export function Navbar({ onNav }: { onNav: (id: string) => void }) { }; return ( -
-
- -
+
+
+
-
+
Jody Holt
@@ -29,12 +31,11 @@ export function Navbar({ onNav }: { onNav: (id: string) => void }) {
- -
-
void }) { ))}
-
diff --git a/src/components/ThemeToggle.tsx b/src/components/ThemeToggle.tsx index 3a0abfe..77d2267 100644 --- a/src/components/ThemeToggle.tsx +++ b/src/components/ThemeToggle.tsx @@ -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(".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 (
- - - {compact ? "Theme" : "Toggle Theme"} - + + {compact ? "Theme" : "Toggle Theme"} +
    {themes.map((t) => (
  • diff --git a/src/index.css b/src/index.css index c936146..956372f 100644 --- a/src/index.css +++ b/src/index.css @@ -48,7 +48,7 @@ html[data-theme="d"] { --color-bg: #0f1014; --color-secondary: #1d1f24; --color-text: #eaecef; - --color-primary: #6c78ff; + --color-primary: #7743d8; --color-tertiary: #a97bff; --color-contrast: #9ca3af; } @@ -69,7 +69,7 @@ html[data-theme="e"] { @layer utilities { /* Mobile / default */ - .bg-hero { + .bg-hero { background: /* Top-right radial accent, similar to desktop */ radial-gradient( 120% 100% at 80% 10%, @@ -78,10 +78,10 @@ html[data-theme="e"] { ), /* Slight linear sweep from top to bottom */ linear-gradient( - 180deg, + 120deg, #0a0d13 0%, - var(--color-bg) 40%, - color-mix(in oklab, var(--color-primary) 10%, var(--color-bg) 90%) + var(--color-bg) 20%, + color-mix(in oklab, var(--color-primary) 15%, var(--color-bg) 90%) 100% ); } @@ -92,7 +92,7 @@ html[data-theme="e"] { background: /* small, softer highlight lower than the portrait rim */ radial-gradient( 95% 70% at 50% 28%, - color-mix(in oklab, var(--hero-core) 18%, transparent 82%) 0%, + color-mix(in oklab, var(--hero-core) 24%, transparent 82%) 0%, transparent 56% ), /* gentle bottom vignette for depth */ @@ -116,12 +116,12 @@ html[data-theme="e"] { html[data-theme="a"] .bg-hero { background: radial-gradient( 135% 120% at 80% 48%, - color-mix(in oklab, var(--color-primary) 65%, black 35%) 0%, - color-mix(in oklab, var(--color-primary) 45%, black 55%) 38%, - transparent 74% + color-mix(in oklab, var(--color-primary) 50%, black 35%) 0%, + color-mix(in oklab, var(--color-primary) 70%, black 55%) 38%, + transparent 90% ), linear-gradient( - 165deg, + 230deg, #080b10 0%, color-mix(in oklab, var(--color-bg) 70%, black 30%) 46%, #0a1324 100% @@ -131,27 +131,27 @@ html[data-theme="e"] { html[data-theme="b"] .bg-hero { background: radial-gradient( 140% 110% at 76% 46%, - color-mix(in oklab, var(--color-primary) 60%, black 40%) 0%, - color-mix(in oklab, var(--color-primary) 40%, black 60%) 36%, - transparent 70% + color-mix(in oklab, var(--color-primary) 50%, black 40%) 0%, + color-mix(in oklab, var(--color-primary) 70%, black 60%) 36%, + transparent 82% ), linear-gradient( - 185deg, + 230deg, #140c0b 0%, - var(--color-bg) 40%, - color-mix(in oklab, var(--color-tertiary) 6%, var(--color-bg) 94%) 100% + var(--color-bg) 20%, + color-mix(in oklab, var(--color-secondary) 6%, var(--color-bg) 94%) 100% ); } /* Theme C – teal/cyan */ html[data-theme="c"] .bg-hero { background: radial-gradient( 140% 120% at 76% 48%, - color-mix(in oklab, var(--color-primary) 58%, black 42%) 0%, - color-mix(in oklab, var(--color-primary) 40%, black 60%) 36%, - transparent 72% + color-mix(in oklab, var(--color-primary) 50%, black 42%) 0%, + color-mix(in oklab, var(--color-primary) 70%, black 60%) 36%, + transparent 82% ), linear-gradient( - 165deg, + 230deg, #081016 0%, color-mix(in oklab, var(--color-bg) 62%, black 38%) 44%, #0a1822 100% @@ -162,12 +162,12 @@ html[data-theme="e"] { html[data-theme="d"] .bg-hero { background: radial-gradient( 135% 120% at 80% 48%, - color-mix(in oklab, var(--color-primary) 60%, black 40%) 0%, - color-mix(in oklab, var(--color-primary) 38%, black 62%) 36%, - transparent 72% + color-mix(in oklab, var(--color-primary) 50%, black 40%) 0%, + color-mix(in oklab, var(--color-primary) 70%, black 62%) 36%, + transparent 82% ), linear-gradient( - 165deg, + 230deg, #090a10 0%, color-mix(in oklab, var(--color-bg) 68%, black 32%) 46%, #111328 100% @@ -178,12 +178,12 @@ html[data-theme="e"] { html[data-theme="e"] .bg-hero { background: radial-gradient( 140% 120% at 78% 48%, - color-mix(in oklab, var(--color-primary) 58%, black 42%) 0%, - color-mix(in oklab, var(--color-primary) 38%, black 62%) 34%, - transparent 70% + color-mix(in oklab, var(--color-primary) 50%, black 42%) 0%, + color-mix(in oklab, var(--color-primary) 70%, black 62%) 34%, + transparent 82% ), linear-gradient( - 165deg, + 230deg, #07100e 0%, color-mix(in oklab, var(--color-bg) 64%, black 36%) 44%, #0a1c1a 100% @@ -198,12 +198,19 @@ html[data-theme="e"] { pointer-events: none; /* left-to-right fade of darkness */ background: linear-gradient( - 90deg, + 270deg, rgba(0, 0, 0, 0.5) 0%, - rgba(0, 0, 0, 0.34) 30%, - rgba(0, 0, 0, 0.18) 42%, + rgba(0, 0, 0, 0.34) 16%, + rgba(0, 0, 0, 0.18) 35%, rgba(0, 0, 0, 0) 50% - ); + ), + linear-gradient( + 270deg, + rgba(0,0,0,0.6) 0%, + rgba(0,0,0,0.48) 25%, + rgba(0,0,0,0.1) 60% + ); + ; z-index: 0; } /* keep content above the overlay */ @@ -231,4 +238,53 @@ html[data-theme="e"] { ); box-shadow: inset 0 0 24px rgba(0, 0, 0, 0.35); } -} \ No newline at end of file +} + +/* ── Keyframes ─────────────────────────────────────────── */ +/* ── Keyframes (unchanged) ───────────────────────────── */ +@keyframes ui-fade-in { from{opacity:0;transform:translateY(6px)} to{opacity:1;transform:translateY(0)} } +@keyframes ui-pop-in { from{opacity:0;transform:scale(.96);filter:blur(2px)} to{opacity:1;transform:scale(1);filter:blur(0)} } +@keyframes ui-fade { from{opacity:0} to{opacity:1} } +/* Old→new gradient crossfade */ +@keyframes hero-xfade-out { from { opacity: 1 } to { opacity: 0 } } + +/* When html has .hero-xfade, paint the OLD gradient on ::after and fade it out */ +html.hero-xfade .bg-hero { + position: relative; /* anchor overlay */ +} +html.hero-xfade .bg-hero::after { + content: ""; + position: absolute; + inset: 0; + z-index: 2; /* above everything but below menus if needed */ + pointer-events: none; + background-image: var(--hero-bg-prev, none); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + animation: hero-xfade-out .55s ease-out forwards; /* match your new durations */ +} + +/* Ensure the base gradient is behind content as usual */ +.bg-hero > * { position: relative; z-index: 3; } + + +/* Respect reduced motion (unchanged) */ +@media (prefers-reduced-motion: reduce) { + * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; } +} + +/* ── Helpers (longer durations) ──────────────────────── */ +.anim-base { transition: transform .24s ease, opacity .24s ease, filter .24s ease, color .24s ease, background-color .24s ease, border-color .24s ease; } +.anim-fade-in{ animation: ui-fade-in .55s cubic-bezier(.22,.61,.36,1) both; } /* 550ms */ +.anim-pop-in { animation: ui-pop-in .48s cubic-bezier(.22,.61,.36,1) both; } /* 480ms */ +.anim-fade { animation: ui-fade .45s ease-out both; } /* 450ms */ + +/* Optional: slightly gentler hover/tap */ +.hover-pop:hover { transform: translateY(-2px) scale(1.03); transition-duration: .24s; } +.hover-pop:active { transform: translateY(0) scale(.98); transition-duration: .14s; } + +/* ── Theme fade-on-switch (keeps it simple) ──────────── */ +/* When the theme changes (html[data-theme] switches), the hero softly fades in */ +html[data-theme] .bg-hero { animation: ui-fade .5s ease-out both; } /* 500ms */ +