Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "themockingjet.github.io",
"private": true,
"version": "1.0.0",
"version": "1.2.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
11 changes: 6 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const Skills = lazy(() => import('./components/Skills/Skills'))
const portfolio = parsePortfolio(rawPortfolio)

export const THEMES = [
{ id: 'warm', label: 'Warm', accent: '#5e8a70' },
{ id: 'amber', label: 'Amber', accent: '#f59e0b' },
{ id: 'sage', label: 'Sage', accent: '#5e8a70' },
{ id: 'ocean', label: 'Ocean', accent: '#4a9eff' },
{ id: 'ember', label: 'Ember', accent: '#e07840' },
{ id: 'violet', label: 'Violet', accent: '#8b67e8' },
Expand All @@ -31,16 +32,16 @@ const REVEAL = {

export default function App() {
const [dark, setDark] = useState(true)
const [theme, setTheme] = useState<ThemeId>('warm')
const [theme, setTheme] = useState<ThemeId>('amber')
const toggleDark = () => setDark((d) => !d)

useEffect(() => {
if (dark) document.documentElement.removeAttribute('data-dark')
else document.documentElement.setAttribute('data-dark', '0')
if (dark) document.documentElement.removeAttribute('data-mode')
else document.documentElement.setAttribute('data-mode', 'light')
}, [dark])

useEffect(() => {
if (theme === 'warm') document.documentElement.removeAttribute('data-theme')
if (theme === 'amber') document.documentElement.removeAttribute('data-theme')
else document.documentElement.setAttribute('data-theme', theme)
}, [theme])

Expand Down
60 changes: 7 additions & 53 deletions src/components/About/About.module.css
Original file line number Diff line number Diff line change
@@ -1,46 +1,21 @@
/* Section container */
.about {
composes: section-grid from global;
position: relative;
padding: var(--space-16) 0;
overflow: visible;
}

/* Ambient glow — centered on watermark text */
.about::after {
content: '';
position: absolute;
left: 5%;
top: 30%;
width: 60vw;
height: 60vw;
transform: translate(-20%, -50%);
background: radial-gradient(circle, var(--color-accent-glow) 0%, transparent 60%);
left: -10vw;
bottom: -8vw;
width: 45vw;
height: 45vw;
background: radial-gradient(ellipse at center, color-mix(in srgb, var(--color-accent) 10%, transparent) 0%, transparent 65%);
pointer-events: none;
z-index: 0;
opacity: 0.35;
}

/* Background watermark */
.decor {
position: absolute;
left: 5%;
top: 30%;
font-size: 22vw;
font-weight: 800;
line-height: 1;
white-space: nowrap;
background: radial-gradient(ellipse at center,
color-mix(in srgb, var(--color-accent) 35%, transparent) 0%,
color-mix(in srgb, var(--color-accent) 20%, transparent) 40%,
color-mix(in srgb, var(--color-accent) 8%, transparent) 70%,
transparent 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
pointer-events: none;
user-select: none;
letter-spacing: -0.04em;
opacity: 0.5;
}

.inner {
Expand Down Expand Up @@ -71,17 +46,6 @@
.prose {
max-width: 58ch;
position: relative;
padding-left: var(--space-6);
}

.prose::before {
content: '';
position: absolute;
left: 0;
top: 4px;
bottom: 4px;
width: 2px;
background: linear-gradient(to bottom, var(--color-accent), transparent);
}

/* Paragraph block (one per intent) */
Expand Down Expand Up @@ -126,16 +90,6 @@
border-bottom: 1px solid transparent;
}

@media (max-width: 1024px) {
.decor {
display: none;
}

.about::after {
display: none;
}
}

@media (max-width: 767px) {
.about {
padding: var(--space-12) 0;
Expand Down
20 changes: 3 additions & 17 deletions src/components/About/About.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { motion, AnimatePresence, useScroll, useTransform } from 'motion/react'
import { motion, AnimatePresence } from 'motion/react'
import { useEffect, useState, useRef } from 'react'
import styles from './About.module.css'
import type { AboutData } from '../../lib/parsePortfolio'
import { EASE, STAGGER } from '../../lib/motion'
import { EASE, STAGGER, FADE_UP } from '../../lib/motion'

interface AboutProps {
data: AboutData
Expand All @@ -13,11 +13,6 @@ const FADE_MS = 0.35

const ENTER = STAGGER

const SLOT_ENTER = {
hidden: { opacity: 0, y: 12 },
show: { opacity: 1, y: 0, transition: { duration: 0.55, ease: EASE } },
}

function WordSlot({ variants, personaIdx }: { variants: string[]; personaIdx: number }) {
const [hasSwapped, setHasSwapped] = useState(false)
const prevIdx = useRef(personaIdx)
Expand Down Expand Up @@ -60,12 +55,6 @@ export default function About({ data }: AboutProps) {
const [ready, setReady] = useState(false)
const sectionRef = useRef<HTMLElement>(null)

const { scrollYProgress } = useScroll({
target: sectionRef,
offset: ['start end', 'end start'],
})
const decorY = useTransform(scrollYProgress, [0, 1], [70, -110])

useEffect(() => {
const t = setTimeout(() => setReady(true), 1800)
return () => clearTimeout(t)
Expand All @@ -82,9 +71,6 @@ export default function About({ data }: AboutProps) {

return (
<section ref={sectionRef} className={styles.about} aria-label="About">
<motion.span className={styles.decor} aria-hidden="true" style={{ y: decorY }}>
About
</motion.span>
<div className={styles.inner}>
<motion.h2
className={styles.heading}
Expand Down Expand Up @@ -128,7 +114,7 @@ export default function About({ data }: AboutProps) {
viewport={{ once: true, margin: '-60px' }}
>
{slots.map(({ label, segments }, i) => (
<motion.div key={label} className={styles.slot} variants={SLOT_ENTER}>
<motion.div key={label} className={styles.slot} variants={FADE_UP}>
<span className={styles.intent}>// {label}</span>
<p className={`${styles.paragraph} ${i === 0 ? styles.lead : ''}`}>
{segments.map((seg, j) =>
Expand Down
9 changes: 2 additions & 7 deletions src/components/Hero/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,12 @@ import { motion, useScroll, useTransform } from 'motion/react'
import { useEffect, useRef, useState } from 'react'
import styles from './Hero.module.css'
import type { HeroData } from '../../lib/parsePortfolio'
import { EASE } from '../../lib/motion'
import { EASE, STAGGER_DELAY } from '../../lib/motion'

interface HeroProps {
data: HeroData
}

const container = {
hidden: {},
show: { transition: { staggerChildren: 0.08, delayChildren: 0.05 } },
}

const item = {
hidden: { opacity: 0, y: 18 },
show: { opacity: 1, y: 0, transition: { duration: 0.65, ease: EASE } },
Expand Down Expand Up @@ -90,7 +85,7 @@ export default function Hero({ data }: HeroProps) {
<motion.div
className={styles.content}
style={{ y: contentY }}
variants={container}
variants={STAGGER_DELAY}
initial="hidden"
animate="show"
>
Expand Down
87 changes: 31 additions & 56 deletions src/components/Projects/Projects.module.css
Original file line number Diff line number Diff line change
@@ -1,46 +1,21 @@
/* Section container */
.projects {
composes: section-grid from global;
position: relative;
padding: var(--space-16) 0;
overflow: visible;
}

/* Ambient glow — centered on watermark text */
.projects::after {
content: '';
position: absolute;
left: 5%;
top: 50%;
width: 60vw;
height: 60vw;
transform: translate(-20%, -50%);
background: radial-gradient(circle, var(--color-accent-glow) 0%, transparent 60%);
right: -5vw;
top: -6vw;
width: 40vw;
height: 40vw;
background: radial-gradient(ellipse at center, color-mix(in srgb, var(--color-accent) 8%, transparent) 0%, transparent 65%);
pointer-events: none;
z-index: 0;
opacity: 0.4;
}

/* Background watermark */
.decor {
position: absolute;
left: 5%;
top: 50%;
font-size: 22vw;
font-weight: 800;
line-height: 1;
white-space: nowrap;
background: radial-gradient(ellipse at center,
color-mix(in srgb, var(--color-accent) 35%, transparent) 0%,
color-mix(in srgb, var(--color-accent) 20%, transparent) 40%,
color-mix(in srgb, var(--color-accent) 8%, transparent) 70%,
transparent 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
pointer-events: none;
user-select: none;
letter-spacing: -0.04em;
opacity: 0.5;
}

.inner {
Expand All @@ -66,9 +41,11 @@
.card {
--card-accent: var(--color-accent);
position: relative;
background: var(--color-bg-surface);
border: 1px dashed var(--color-border);
border-radius: var(--radius-md);
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 8px;
padding: var(--space-5) var(--space-5) var(--space-5) var(--space-6);
will-change: transform, opacity;
display: grid;
Expand All @@ -77,10 +54,12 @@
column-gap: var(--space-4);
row-gap: var(--space-2);
overflow: hidden;
box-shadow: 0 2px 16px -4px rgba(0, 0, 0, 0.3);
transition:
box-shadow 0.3s ease,
border-color 0.3s ease,
background 0.3s ease,
box-shadow 0.3s ease;
transform 0.3s ease;
}

/* Corner bracket — top-left */
Expand Down Expand Up @@ -115,11 +94,12 @@
}

.card:hover {
border-color: color-mix(in srgb, var(--color-border) 40%, var(--color-accent));
background: var(--color-bg-elevated);
transform: translateY(-2px);
border-color: rgba(255, 255, 255, 0.12);
background: rgba(255, 255, 255, 0.05);
box-shadow:
0 0 0 1px var(--color-accent-dim),
0 4px 24px -4px rgba(0, 0, 0, 0.4);
0 4px 24px -4px rgba(0, 0, 0, 0.4),
0 0 0 1px var(--color-accent-dim);
}

.card:hover::before,
Expand Down Expand Up @@ -330,21 +310,23 @@
gap: 4px;
font-family: var(--font-mono);
font-size: var(--text-xs);
color: var(--color-text-faint);
background: none;
border: 1px dashed var(--color-border);
color: var(--color-text-muted);
background: var(--color-bg-hover);
border: 1px solid var(--color-border);
border-radius: 2px;
padding: 3px 10px;
padding: 4px 12px;
letter-spacing: 0.04em;
text-transform: uppercase;
width: fit-content;
margin-top: var(--space-2);
transition: color 0.2s ease, border-color 0.2s ease;
cursor: pointer;
transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.expandBtn:hover {
color: var(--color-accent);
border-color: var(--color-accent);
background: var(--color-accent-dim);
}

/* Details panel */
Expand Down Expand Up @@ -417,20 +399,13 @@
opacity: 1;
}

.archivedList .card::before {
.archivedList .card::before,
.archivedList .card::after,
.archivedList .cornerBL,
.archivedList .cornerBR {
border-color: var(--color-text-faint);
}

@media (max-width: 1024px) {
.decor {
display: none;
}

.projects::after {
display: none;
}
}

@media (max-width: 767px) {
.projects {
padding: var(--space-12) 0;
Expand Down
Loading
Loading